sassc 1.11.4 → 1.12.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 (137) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +2 -2
  3. data/CODE_OF_CONDUCT.md +10 -0
  4. data/README.md +4 -1
  5. data/ext/libsass/.editorconfig +1 -1
  6. data/ext/libsass/.github/CONTRIBUTING.md +7 -7
  7. data/ext/libsass/.github/ISSUE_TEMPLATE.md +31 -6
  8. data/ext/libsass/.gitignore +3 -0
  9. data/ext/libsass/.travis.yml +37 -18
  10. data/ext/libsass/GNUmakefile.am +23 -37
  11. data/ext/libsass/Makefile +10 -6
  12. data/ext/libsass/Makefile.conf +3 -0
  13. data/ext/libsass/Readme.md +68 -63
  14. data/ext/libsass/appveyor.yml +7 -3
  15. data/ext/libsass/configure.ac +10 -14
  16. data/ext/libsass/docs/api-context-internal.md +29 -21
  17. data/ext/libsass/docs/api-context.md +26 -6
  18. data/ext/libsass/docs/api-doc.md +49 -16
  19. data/ext/libsass/docs/api-function-example.md +1 -1
  20. data/ext/libsass/docs/api-function.md +31 -7
  21. data/ext/libsass/docs/api-importer.md +19 -19
  22. data/ext/libsass/docs/api-value.md +4 -2
  23. data/ext/libsass/docs/build-on-windows.md +4 -4
  24. data/ext/libsass/docs/build-with-mingw.md +3 -3
  25. data/ext/libsass/docs/build.md +9 -9
  26. data/ext/libsass/docs/custom-functions-internal.md +10 -8
  27. data/ext/libsass/docs/implementations.md +20 -8
  28. data/ext/libsass/docs/unicode.md +16 -10
  29. data/ext/libsass/include/sass/base.h +0 -3
  30. data/ext/libsass/include/sass/context.h +20 -2
  31. data/ext/libsass/include/sass/functions.h +31 -0
  32. data/ext/libsass/include/sass/values.h +3 -1
  33. data/ext/libsass/include/sass/version.h +1 -1
  34. data/ext/libsass/include/sass/version.h.in +1 -1
  35. data/ext/libsass/include/sass2scss.h +1 -1
  36. data/ext/libsass/res/resource.rc +6 -6
  37. data/ext/libsass/script/ci-build-libsass +10 -5
  38. data/ext/libsass/script/ci-build-plugin +62 -0
  39. data/ext/libsass/script/ci-install-compiler +1 -1
  40. data/ext/libsass/script/ci-install-deps +4 -7
  41. data/ext/libsass/script/ci-report-coverage +13 -3
  42. data/ext/libsass/script/tap-driver +1 -1
  43. data/ext/libsass/script/tap-runner +1 -1
  44. data/ext/libsass/src/GNUmakefile.am +1 -1
  45. data/ext/libsass/src/ast.cpp +537 -762
  46. data/ext/libsass/src/ast.hpp +377 -419
  47. data/ext/libsass/src/ast_def_macros.hpp +26 -1
  48. data/ext/libsass/src/ast_fwd_decl.cpp +29 -0
  49. data/ext/libsass/src/ast_fwd_decl.hpp +94 -21
  50. data/ext/libsass/src/b64/encode.h +3 -1
  51. data/ext/libsass/src/backtrace.cpp +46 -0
  52. data/ext/libsass/src/backtrace.hpp +7 -54
  53. data/ext/libsass/src/bind.cpp +72 -50
  54. data/ext/libsass/src/bind.hpp +0 -1
  55. data/ext/libsass/src/cencode.c +6 -0
  56. data/ext/libsass/src/check_nesting.cpp +157 -135
  57. data/ext/libsass/src/check_nesting.hpp +11 -10
  58. data/ext/libsass/src/color_maps.cpp +10 -6
  59. data/ext/libsass/src/color_maps.hpp +6 -8
  60. data/ext/libsass/src/constants.cpp +4 -3
  61. data/ext/libsass/src/constants.hpp +4 -3
  62. data/ext/libsass/src/context.cpp +110 -47
  63. data/ext/libsass/src/context.hpp +11 -1
  64. data/ext/libsass/src/cssize.cpp +105 -94
  65. data/ext/libsass/src/cssize.hpp +4 -5
  66. data/ext/libsass/src/debugger.hpp +247 -244
  67. data/ext/libsass/src/emitter.cpp +30 -6
  68. data/ext/libsass/src/emitter.hpp +7 -0
  69. data/ext/libsass/src/environment.cpp +67 -16
  70. data/ext/libsass/src/environment.hpp +28 -7
  71. data/ext/libsass/src/error_handling.cpp +92 -64
  72. data/ext/libsass/src/error_handling.hpp +64 -43
  73. data/ext/libsass/src/eval.cpp +494 -544
  74. data/ext/libsass/src/eval.hpp +17 -23
  75. data/ext/libsass/src/expand.cpp +182 -154
  76. data/ext/libsass/src/expand.hpp +4 -5
  77. data/ext/libsass/src/extend.cpp +299 -291
  78. data/ext/libsass/src/extend.hpp +46 -11
  79. data/ext/libsass/src/file.cpp +103 -36
  80. data/ext/libsass/src/file.hpp +21 -4
  81. data/ext/libsass/src/functions.cpp +561 -312
  82. data/ext/libsass/src/functions.hpp +8 -5
  83. data/ext/libsass/src/inspect.cpp +108 -53
  84. data/ext/libsass/src/inspect.hpp +5 -2
  85. data/ext/libsass/src/lexer.cpp +15 -7
  86. data/ext/libsass/src/lexer.hpp +13 -4
  87. data/ext/libsass/src/listize.cpp +3 -2
  88. data/ext/libsass/src/listize.hpp +0 -1
  89. data/ext/libsass/src/memory/SharedPtr.cpp +16 -18
  90. data/ext/libsass/src/memory/SharedPtr.hpp +47 -43
  91. data/ext/libsass/src/node.cpp +34 -38
  92. data/ext/libsass/src/node.hpp +6 -8
  93. data/ext/libsass/src/operation.hpp +2 -2
  94. data/ext/libsass/src/operators.cpp +240 -0
  95. data/ext/libsass/src/operators.hpp +30 -0
  96. data/ext/libsass/src/output.cpp +22 -20
  97. data/ext/libsass/src/parser.cpp +719 -358
  98. data/ext/libsass/src/parser.hpp +57 -22
  99. data/ext/libsass/src/plugins.cpp +28 -10
  100. data/ext/libsass/src/position.cpp +21 -3
  101. data/ext/libsass/src/position.hpp +2 -1
  102. data/ext/libsass/src/prelexer.cpp +104 -19
  103. data/ext/libsass/src/prelexer.hpp +10 -3
  104. data/ext/libsass/src/remove_placeholders.cpp +9 -10
  105. data/ext/libsass/src/remove_placeholders.hpp +1 -5
  106. data/ext/libsass/src/sass.cpp +62 -4
  107. data/ext/libsass/src/sass.hpp +5 -2
  108. data/ext/libsass/src/sass_context.cpp +96 -58
  109. data/ext/libsass/src/sass_context.hpp +7 -5
  110. data/ext/libsass/src/sass_functions.cpp +63 -1
  111. data/ext/libsass/src/sass_functions.hpp +19 -1
  112. data/ext/libsass/src/sass_util.cpp +3 -3
  113. data/ext/libsass/src/sass_util.hpp +4 -4
  114. data/ext/libsass/src/sass_values.cpp +42 -39
  115. data/ext/libsass/src/sass_values.hpp +2 -1
  116. data/ext/libsass/src/source_map.cpp +16 -18
  117. data/ext/libsass/src/subset_map.cpp +6 -8
  118. data/ext/libsass/src/subset_map.hpp +6 -6
  119. data/ext/libsass/src/to_c.cpp +2 -2
  120. data/ext/libsass/src/to_value.cpp +8 -3
  121. data/ext/libsass/src/to_value.hpp +1 -0
  122. data/ext/libsass/src/units.cpp +349 -45
  123. data/ext/libsass/src/units.hpp +39 -22
  124. data/ext/libsass/src/utf8/checked.h +7 -0
  125. data/ext/libsass/src/utf8/unchecked.h +7 -0
  126. data/ext/libsass/src/utf8_string.cpp +1 -1
  127. data/ext/libsass/src/util.cpp +139 -45
  128. data/ext/libsass/src/util.hpp +4 -7
  129. data/ext/libsass/src/values.cpp +15 -23
  130. data/ext/libsass/win/libsass.sln +13 -2
  131. data/ext/libsass/win/libsass.sln.DotSettings +9 -0
  132. data/ext/libsass/win/libsass.targets +3 -0
  133. data/ext/libsass/win/libsass.vcxproj.filters +9 -0
  134. data/lib/sassc/version.rb +1 -1
  135. data/sassc.gemspec +1 -1
  136. data/test/native_test.rb +1 -1
  137. metadata +11 -4
@@ -13,18 +13,16 @@ namespace Sass {
13
13
  class Listize;
14
14
  class Context;
15
15
  class Eval;
16
- typedef Environment<AST_Node_Obj> Env;
17
16
  struct Backtrace;
18
17
 
19
18
  class Expand : public Operation_CRTP<Statement_Ptr, Expand> {
20
19
  public:
21
20
 
22
21
  Env* environment();
23
- Context& context();
24
22
  Selector_List_Obj selector();
25
- Backtrace* backtrace();
26
23
 
27
24
  Context& ctx;
25
+ Backtraces& traces;
28
26
  Eval eval;
29
27
  size_t recursions;
30
28
  bool in_keyframes;
@@ -37,7 +35,8 @@ namespace Sass {
37
35
  std::vector<AST_Node_Obj> call_stack;
38
36
  std::vector<Selector_List_Obj> selector_stack;
39
37
  std::vector<Media_Block_Ptr> media_block_stack;
40
- std::vector<Backtrace*> backtrace_stack;
38
+
39
+ Boolean_Obj bool_true;
41
40
 
42
41
  Statement_Ptr fallback_impl(AST_Node_Ptr n);
43
42
 
@@ -45,7 +44,7 @@ namespace Sass {
45
44
  void expand_selector_list(Selector_Obj, Selector_List_Obj extender);
46
45
 
47
46
  public:
48
- Expand(Context&, Env*, Backtrace*, std::vector<Selector_List_Obj>* stack = NULL);
47
+ Expand(Context&, Env*, std::vector<Selector_List_Obj>* stack = NULL);
49
48
  ~Expand() { }
50
49
 
51
50
  Block_Ptr operator()(Block_Ptr);
@@ -4,6 +4,7 @@
4
4
  #include "backtrace.hpp"
5
5
  #include "paths.hpp"
6
6
  #include "parser.hpp"
7
+ #include "expand.hpp"
7
8
  #include "node.hpp"
8
9
  #include "sass_util.hpp"
9
10
  #include "remove_placeholders.hpp"
@@ -61,8 +62,6 @@
61
62
  namespace Sass {
62
63
 
63
64
 
64
- typedef std::pair<Complex_Selector_Obj, Compound_Selector_Obj> ExtensionPair;
65
- typedef std::vector<ExtensionPair> SubsetMapEntries;
66
65
 
67
66
  #ifdef DEBUG
68
67
 
@@ -111,11 +110,6 @@ namespace Sass {
111
110
  }
112
111
  }
113
112
 
114
- // Print a string representation of a Compound_Selector
115
- typedef std::pair<Compound_Selector_Obj, Complex_Selector_Obj> SelsNewSeqPair;
116
- typedef std::vector<SelsNewSeqPair> SelsNewSeqPairCollection;
117
-
118
-
119
113
  // Print a string representation of a Compound_Selector
120
114
  static void printCompoundSelector(Compound_Selector_Ptr pCompoundSelector, const char* message=NULL, bool newline=true) {
121
115
 
@@ -186,14 +180,14 @@ namespace Sass {
186
180
  }
187
181
  }
188
182
 
189
- static void printSelsNewSeqPairCollection(SelsNewSeqPairCollection& collection, const char* message=NULL, bool newline=true) {
183
+ static void printSelsNewSeqPairCollection(SubSetMapLookups& collection, const char* message=NULL, bool newline=true) {
190
184
 
191
185
  if (message) {
192
186
  std::cerr << message;
193
187
  }
194
188
  bool first = true;
195
189
  std::cerr << "[";
196
- for(SelsNewSeqPair& pair : collection) {
190
+ for(SubSetMapLookup& pair : collection) {
197
191
  if (first) {
198
192
  first = false;
199
193
  } else {
@@ -212,8 +206,8 @@ namespace Sass {
212
206
  }
213
207
  }
214
208
 
215
- // Print a string representation of a SourcesSet
216
- static void printSourcesSet(SourcesSet& sources, Context& ctx, const char* message=NULL, bool newline=true) {
209
+ // Print a string representation of a ComplexSelectorSet
210
+ static void printSourcesSet(ComplexSelectorSet& sources, const char* message=NULL, bool newline=true) {
217
211
 
218
212
  if (message) {
219
213
  std::cerr << message;
@@ -223,17 +217,17 @@ namespace Sass {
223
217
  // the differences we see when debug printing.
224
218
  typedef std::deque<std::string> SourceStrings;
225
219
  SourceStrings sourceStrings;
226
- for (SourcesSet::iterator iterator = sources.begin(), iteratorEnd = sources.end(); iterator != iteratorEnd; ++iterator) {
220
+ for (ComplexSelectorSet::iterator iterator = sources.begin(), iteratorEnd = sources.end(); iterator != iteratorEnd; ++iterator) {
227
221
  Complex_Selector_Ptr pSource = *iterator;
228
222
  std::stringstream sstream;
229
- sstream << complexSelectorToNode(pSource, ctx);
223
+ sstream << complexSelectorToNode(pSource);
230
224
  sourceStrings.push_back(sstream.str());
231
225
  }
232
226
 
233
227
  // Sort to get consistent output
234
228
  std::sort(sourceStrings.begin(), sourceStrings.end());
235
229
 
236
- std::cerr << "SourcesSet[";
230
+ std::cerr << "ComplexSelectorSet[";
237
231
  for (SourceStrings::iterator iterator = sourceStrings.begin(), iteratorEnd = sourceStrings.end(); iterator != iteratorEnd; ++iterator) {
238
232
  std::string source = *iterator;
239
233
  if (iterator != sourceStrings.begin()) {
@@ -249,10 +243,10 @@ namespace Sass {
249
243
  }
250
244
 
251
245
 
252
- std::ostream& operator<<(std::ostream& os, SubsetMapEntries& entries) {
246
+ std::ostream& operator<<(std::ostream& os, SubSetMapPairs& entries) {
253
247
  os << "SUBSET_MAP_ENTRIES[";
254
248
 
255
- for (SubsetMapEntries::iterator iterator = entries.begin(), endIterator = entries.end(); iterator != endIterator; ++iterator) {
249
+ for (SubSetMapPairs::iterator iterator = entries.begin(), endIterator = entries.end(); iterator != endIterator; ++iterator) {
256
250
  Complex_Selector_Obj pExtComplexSelector = iterator->first; // The selector up to where the @extend is (ie, the thing to merge)
257
251
  Compound_Selector_Obj pExtCompoundSelector = iterator->second; // The stuff after the @extend
258
252
 
@@ -286,17 +280,16 @@ namespace Sass {
286
280
  }
287
281
  #endif
288
282
 
289
- static bool parentSuperselector(Complex_Selector_Ptr pOne, Complex_Selector_Ptr pTwo, Context& ctx) {
283
+ static bool parentSuperselector(Complex_Selector_Ptr pOne, Complex_Selector_Ptr pTwo) {
290
284
  // TODO: figure out a better way to create a Complex_Selector from scratch
291
285
  // TODO: There's got to be a better way. This got ugly quick...
292
- Position noPosition(-1, -1, -1);
293
286
  Element_Selector_Obj fakeParent = SASS_MEMORY_NEW(Element_Selector, ParserState("[FAKE]"), "temp");
294
287
  Compound_Selector_Obj fakeHead = SASS_MEMORY_NEW(Compound_Selector, ParserState("[FAKE]"), 1 /*size*/);
295
- fakeHead->elements().push_back(&fakeParent);
296
- Complex_Selector_Obj fakeParentContainer = SASS_MEMORY_NEW(Complex_Selector, ParserState("[FAKE]"), Complex_Selector::ANCESTOR_OF, &fakeHead /*head*/, NULL /*tail*/);
288
+ fakeHead->elements().push_back(fakeParent);
289
+ Complex_Selector_Obj fakeParentContainer = SASS_MEMORY_NEW(Complex_Selector, ParserState("[FAKE]"), Complex_Selector::ANCESTOR_OF, fakeHead /*head*/, NULL /*tail*/);
297
290
 
298
- pOne->set_innermost(&fakeParentContainer, Complex_Selector::ANCESTOR_OF);
299
- pTwo->set_innermost(&fakeParentContainer, Complex_Selector::ANCESTOR_OF);
291
+ pOne->set_innermost(fakeParentContainer, Complex_Selector::ANCESTOR_OF);
292
+ pTwo->set_innermost(fakeParentContainer, Complex_Selector::ANCESTOR_OF);
300
293
 
301
294
  bool isSuperselector = pOne->is_superselector_of(pTwo);
302
295
 
@@ -306,19 +299,19 @@ namespace Sass {
306
299
  return isSuperselector;
307
300
  }
308
301
 
309
- void nodeToComplexSelectorDeque(const Node& node, ComplexSelectorDeque& out, Context& ctx) {
302
+ void nodeToComplexSelectorDeque(const Node& node, ComplexSelectorDeque& out) {
310
303
  for (NodeDeque::iterator iter = node.collection()->begin(), iterEnd = node.collection()->end(); iter != iterEnd; iter++) {
311
304
  Node& child = *iter;
312
- out.push_back(nodeToComplexSelector(child, ctx));
305
+ out.push_back(nodeToComplexSelector(child));
313
306
  }
314
307
  }
315
308
 
316
- Node complexSelectorDequeToNode(const ComplexSelectorDeque& deque, Context& ctx) {
309
+ Node complexSelectorDequeToNode(const ComplexSelectorDeque& deque) {
317
310
  Node result = Node::createCollection();
318
311
 
319
312
  for (ComplexSelectorDeque::const_iterator iter = deque.begin(), iterEnd = deque.end(); iter != iterEnd; iter++) {
320
313
  Complex_Selector_Obj pChild = *iter;
321
- result.collection()->push_back(complexSelectorToNode(&pChild, ctx));
314
+ result.collection()->push_back(complexSelectorToNode(pChild));
322
315
  }
323
316
 
324
317
  return result;
@@ -326,9 +319,7 @@ namespace Sass {
326
319
 
327
320
  class LcsCollectionComparator {
328
321
  public:
329
- LcsCollectionComparator(Context& ctx) : mCtx(ctx) {}
330
-
331
- Context& mCtx;
322
+ LcsCollectionComparator() {}
332
323
 
333
324
  bool operator()(Complex_Selector_Obj pOne, Complex_Selector_Obj pTwo, Complex_Selector_Obj& pOut) const {
334
325
  /*
@@ -341,7 +332,7 @@ namespace Sass {
341
332
  end
342
333
  */
343
334
 
344
- if (selectors_equal(*pOne, *pTwo, true /*simpleSelectorOrderDependent*/)) {
335
+ if (*pOne == *pTwo) {
345
336
  pOut = pOne;
346
337
  return true;
347
338
  }
@@ -350,12 +341,12 @@ namespace Sass {
350
341
  return false;
351
342
  }
352
343
 
353
- if (parentSuperselector(&pOne, &pTwo, mCtx)) {
344
+ if (parentSuperselector(pOne, pTwo)) {
354
345
  pOut = pTwo;
355
346
  return true;
356
347
  }
357
348
 
358
- if (parentSuperselector(&pTwo, &pOne, mCtx)) {
349
+ if (parentSuperselector(pTwo, pOne)) {
359
350
  pOut = pOne;
360
351
  return true;
361
352
  }
@@ -420,7 +411,7 @@ namespace Sass {
420
411
  for (size_t j = 1; j < y.size(); j++) {
421
412
  Complex_Selector_Obj pCompareOut;
422
413
 
423
- if (comparator(&x[i], &y[j], pCompareOut)) {
414
+ if (comparator(x[i], y[j], pCompareOut)) {
424
415
  c[i][j] = c[i - 1][j - 1] + 1;
425
416
  } else {
426
417
  c[i][j] = std::max(c[i][j - 1], c[i - 1][j]);
@@ -445,7 +436,7 @@ namespace Sass {
445
436
 
446
437
  http://en.wikipedia.org/wiki/Longest_common_subsequence_problem
447
438
  */
448
- void lcs(ComplexSelectorDeque& x, ComplexSelectorDeque& y, const LcsCollectionComparator& comparator, Context& ctx, ComplexSelectorDeque& out) {
439
+ void lcs(ComplexSelectorDeque& x, ComplexSelectorDeque& y, const LcsCollectionComparator& comparator, ComplexSelectorDeque& out) {
449
440
  //DEBUG_PRINTLN(LCS, "LCS: X=" << x << " Y=" << y)
450
441
  // TODO: make printComplexSelectorDeque and use DEBUG_EXEC AND DEBUG_PRINTLN HERE to get equivalent output
451
442
 
@@ -525,7 +516,7 @@ namespace Sass {
525
516
  /*
526
517
  - IMPROVEMENT: We could probably work directly in the output trimmed deque.
527
518
  */
528
- static Node trim(Node& seqses, Context& ctx, bool isReplace) {
519
+ Node Extend::trim(Node& seqses, bool isReplace) {
529
520
  // See the comments in the above ruby code before embarking on understanding this function.
530
521
 
531
522
  // Avoid poor performance in extreme cases.
@@ -558,7 +549,7 @@ namespace Sass {
558
549
  for (NodeDeque::iterator seqs1Iter = seqs1.collection()->begin(), seqs1EndIter = seqs1.collection()->end(); seqs1Iter != seqs1EndIter; ++seqs1Iter) {
559
550
  Node& seq1 = *seqs1Iter;
560
551
 
561
- Complex_Selector_Obj pSeq1 = nodeToComplexSelector(seq1, ctx);
552
+ Complex_Selector_Obj pSeq1 = nodeToComplexSelector(seq1);
562
553
 
563
554
  // Compute the maximum specificity. This requires looking at the "sources" of the sequence. See SimpleSequence.sources in the ruby code
564
555
  // for a good description of sources.
@@ -569,12 +560,12 @@ namespace Sass {
569
560
  // best guess at this point is that we're cloning an object somewhere and maintaining the sources when we shouldn't be. This is purely
570
561
  // a guess though.
571
562
  unsigned long maxSpecificity = isReplace ? pSeq1->specificity() : 0;
572
- SourcesSet sources = pSeq1->sources();
563
+ ComplexSelectorSet sources = pSeq1->sources();
573
564
 
574
565
  DEBUG_PRINTLN(TRIM, "TRIM SEQ1: " << seq1)
575
- DEBUG_EXEC(TRIM, printSourcesSet(sources, ctx, "TRIM SOURCES: "))
566
+ DEBUG_EXEC(TRIM, printSourcesSet(sources, "TRIM SOURCES: "))
576
567
 
577
- for (SourcesSet::iterator sourcesSetIterator = sources.begin(), sourcesSetIteratorEnd = sources.end(); sourcesSetIterator != sourcesSetIteratorEnd; ++sourcesSetIterator) {
568
+ for (ComplexSelectorSet::iterator sourcesSetIterator = sources.begin(), sourcesSetIteratorEnd = sources.end(); sourcesSetIterator != sourcesSetIteratorEnd; ++sourcesSetIterator) {
578
569
  const Complex_Selector_Obj& pCurrentSelector = *sourcesSetIterator;
579
570
  maxSpecificity = std::max(maxSpecificity, pCurrentSelector->specificity());
580
571
  }
@@ -605,7 +596,7 @@ namespace Sass {
605
596
  for (NodeDeque::iterator seqs2Iter = seqs2.collection()->begin(), seqs2IterEnd = seqs2.collection()->end(); seqs2Iter != seqs2IterEnd; ++seqs2Iter) {
606
597
  Node& seq2 = *seqs2Iter;
607
598
 
608
- Complex_Selector_Obj pSeq2 = nodeToComplexSelector(seq2, ctx);
599
+ Complex_Selector_Obj pSeq2 = nodeToComplexSelector(seq2);
609
600
 
610
601
  DEBUG_PRINTLN(TRIM, "SEQ2 SPEC: " << pSeq2->specificity())
611
602
  DEBUG_PRINTLN(TRIM, "IS SPEC: " << pSeq2->specificity() << " >= " << maxSpecificity << " " << (pSeq2->specificity() >= maxSpecificity ? "true" : "false"))
@@ -649,19 +640,18 @@ namespace Sass {
649
640
 
650
641
 
651
642
 
652
- static bool parentSuperselector(const Node& one, const Node& two, Context& ctx) {
643
+ static bool parentSuperselector(const Node& one, const Node& two) {
653
644
  // TODO: figure out a better way to create a Complex_Selector from scratch
654
645
  // TODO: There's got to be a better way. This got ugly quick...
655
- Position noPosition(-1, -1, -1);
656
646
  Element_Selector_Obj fakeParent = SASS_MEMORY_NEW(Element_Selector, ParserState("[FAKE]"), "temp");
657
647
  Compound_Selector_Obj fakeHead = SASS_MEMORY_NEW(Compound_Selector, ParserState("[FAKE]"), 1 /*size*/);
658
- fakeHead->elements().push_back(&fakeParent);
659
- Complex_Selector_Obj fakeParentContainer = SASS_MEMORY_NEW(Complex_Selector, ParserState("[FAKE]"), Complex_Selector::ANCESTOR_OF, &fakeHead /*head*/, NULL /*tail*/);
648
+ fakeHead->elements().push_back(fakeParent);
649
+ Complex_Selector_Obj fakeParentContainer = SASS_MEMORY_NEW(Complex_Selector, ParserState("[FAKE]"), Complex_Selector::ANCESTOR_OF, fakeHead /*head*/, NULL /*tail*/);
660
650
 
661
- Complex_Selector_Obj pOneWithFakeParent = nodeToComplexSelector(one, ctx);
662
- pOneWithFakeParent->set_innermost(&fakeParentContainer, Complex_Selector::ANCESTOR_OF);
663
- Complex_Selector_Obj pTwoWithFakeParent = nodeToComplexSelector(two, ctx);
664
- pTwoWithFakeParent->set_innermost(&fakeParentContainer, Complex_Selector::ANCESTOR_OF);
651
+ Complex_Selector_Obj pOneWithFakeParent = nodeToComplexSelector(one);
652
+ pOneWithFakeParent->set_innermost(fakeParentContainer, Complex_Selector::ANCESTOR_OF);
653
+ Complex_Selector_Obj pTwoWithFakeParent = nodeToComplexSelector(two);
654
+ pTwoWithFakeParent->set_innermost(fakeParentContainer, Complex_Selector::ANCESTOR_OF);
665
655
 
666
656
  return pOneWithFakeParent->is_superselector_of(pTwoWithFakeParent);
667
657
  }
@@ -669,14 +659,13 @@ namespace Sass {
669
659
 
670
660
  class ParentSuperselectorChunker {
671
661
  public:
672
- ParentSuperselectorChunker(Node& lcs, Context& ctx) : mLcs(lcs), mCtx(ctx) {}
662
+ ParentSuperselectorChunker(Node& lcs) : mLcs(lcs) {}
673
663
  Node& mLcs;
674
- Context& mCtx;
675
664
 
676
665
  bool operator()(const Node& seq) const {
677
666
  // {|s| parent_superselector?(s.first, lcs.first)}
678
667
  if (seq.collection()->size() == 0) return false;
679
- return parentSuperselector(seq.collection()->front(), mLcs.collection()->front(), mCtx);
668
+ return parentSuperselector(seq.collection()->front(), mLcs.collection()->front());
680
669
  }
681
670
  };
682
671
 
@@ -730,7 +719,7 @@ namespace Sass {
730
719
  }
731
720
 
732
721
  Node chunk2 = Node::createCollection();
733
- while (!chunker(seq2)) {
722
+ while (!seq2.collection()->empty() && !chunker(seq2)) {
734
723
  chunk2.collection()->push_back(seq2.collection()->front());
735
724
  seq2.collection()->pop_front();
736
725
  }
@@ -772,7 +761,7 @@ namespace Sass {
772
761
  }
773
762
 
774
763
 
775
- static Node groupSelectors(Node& seq, Context& ctx) {
764
+ static Node groupSelectors(Node& seq) {
776
765
  Node newSeq = Node::createCollection();
777
766
 
778
767
  Node tail = Node::createCollection();
@@ -832,7 +821,7 @@ namespace Sass {
832
821
  return (newline ? ["\n"] : []) + (ops1.size > ops2.size ? ops1 : ops2)
833
822
  end
834
823
  */
835
- static Node mergeInitialOps(Node& seq1, Node& seq2, Context& ctx) {
824
+ static Node mergeInitialOps(Node& seq1, Node& seq2) {
836
825
  Node ops1 = Node::createCollection();
837
826
  Node ops2 = Node::createCollection();
838
827
 
@@ -846,9 +835,9 @@ namespace Sass {
846
835
 
847
836
  // If neither sequence is a subsequence of the other, they cannot be merged successfully
848
837
  DefaultLcsComparator lcsDefaultComparator;
849
- Node opsLcs = lcs(ops1, ops2, lcsDefaultComparator, ctx);
838
+ Node opsLcs = lcs(ops1, ops2, lcsDefaultComparator);
850
839
 
851
- if (!(nodesEqual(opsLcs, ops1, true) || nodesEqual(opsLcs, ops2, true))) {
840
+ if (!(opsLcs == ops1 || opsLcs == ops2)) {
852
841
  return Node::createNil();
853
842
  }
854
843
 
@@ -923,7 +912,7 @@ namespace Sass {
923
912
  end
924
913
  end
925
914
  */
926
- static Node mergeFinalOps(Node& seq1, Node& seq2, Context& ctx, Node& res) {
915
+ static Node mergeFinalOps(Node& seq1, Node& seq2, Node& res) {
927
916
 
928
917
  Node ops1 = Node::createCollection();
929
918
  Node ops2 = Node::createCollection();
@@ -941,11 +930,11 @@ namespace Sass {
941
930
 
942
931
  if (ops1.collection()->size() > 1 || ops2.collection()->size() > 1) {
943
932
  DefaultLcsComparator lcsDefaultComparator;
944
- Node opsLcs = lcs(ops1, ops2, lcsDefaultComparator, ctx);
933
+ Node opsLcs = lcs(ops1, ops2, lcsDefaultComparator);
945
934
 
946
935
  // If there are multiple operators, something hacky's going on. If one is a supersequence of the other, use that, otherwise give up.
947
936
 
948
- if (!(nodesEqual(opsLcs, ops1, true) || nodesEqual(opsLcs, ops2, true))) {
937
+ if (!(opsLcs == ops1 || opsLcs == ops2)) {
949
938
  return Node::createNil();
950
939
  }
951
940
 
@@ -988,7 +977,7 @@ namespace Sass {
988
977
 
989
978
  Complex_Selector_Obj pMergedWrapper = SASS_MEMORY_CLONE(sel1.selector()); // Clone the Complex_Selector to get back to something we can transform to a node once we replace the head with the unification result
990
979
  // TODO: does subject matter? Ruby: return unless merged = sel1.unify(sel2.members, sel2.subject?)
991
- Compound_Selector_Ptr pMerged = sel1.selector()->head()->unify_with(&sel2.selector()->head(), ctx);
980
+ Compound_Selector_Ptr pMerged = sel1.selector()->head()->unify_with(sel2.selector()->head());
992
981
  pMergedWrapper->head(pMerged);
993
982
 
994
983
  DEBUG_EXEC(ALL, printCompoundSelector(pMerged, "MERGED: "))
@@ -1011,7 +1000,7 @@ namespace Sass {
1011
1000
 
1012
1001
  if (pMerged) {
1013
1002
  Node mergedPerm = Node::createCollection();
1014
- mergedPerm.collection()->push_back(Node::createSelector(&pMergedWrapper, ctx));
1003
+ mergedPerm.collection()->push_back(Node::createSelector(pMergedWrapper));
1015
1004
  mergedPerm.collection()->push_back(Node::createCombinator(Complex_Selector::PRECEDES));
1016
1005
  newRes.collection()->push_back(mergedPerm);
1017
1006
  }
@@ -1025,12 +1014,10 @@ namespace Sass {
1025
1014
  } else if (((op1.combinator() == Complex_Selector::PRECEDES && op2.combinator() == Complex_Selector::ADJACENT_TO)) || ((op1.combinator() == Complex_Selector::ADJACENT_TO && op2.combinator() == Complex_Selector::PRECEDES))) {
1026
1015
 
1027
1016
  Node tildeSel = sel1;
1028
- Node tildeOp = op1;
1029
1017
  Node plusSel = sel2;
1030
1018
  Node plusOp = op2;
1031
1019
  if (op1.combinator() != Complex_Selector::PRECEDES) {
1032
1020
  tildeSel = sel2;
1033
- tildeOp = op2;
1034
1021
  plusSel = sel1;
1035
1022
  plusOp = op1;
1036
1023
  }
@@ -1047,7 +1034,7 @@ namespace Sass {
1047
1034
 
1048
1035
  Complex_Selector_Obj pMergedWrapper = SASS_MEMORY_CLONE(plusSel.selector()); // Clone the Complex_Selector to get back to something we can transform to a node once we replace the head with the unification result
1049
1036
  // TODO: does subject matter? Ruby: merged = plus_sel.unify(tilde_sel.members, tilde_sel.subject?)
1050
- Compound_Selector_Ptr pMerged = plusSel.selector()->head()->unify_with(&tildeSel.selector()->head(), ctx);
1037
+ Compound_Selector_Ptr pMerged = plusSel.selector()->head()->unify_with(tildeSel.selector()->head());
1051
1038
  pMergedWrapper->head(pMerged);
1052
1039
 
1053
1040
  DEBUG_EXEC(ALL, printCompoundSelector(pMerged, "MERGED: "))
@@ -1063,7 +1050,7 @@ namespace Sass {
1063
1050
 
1064
1051
  if (pMerged) {
1065
1052
  Node mergedPerm = Node::createCollection();
1066
- mergedPerm.collection()->push_back(Node::createSelector(&pMergedWrapper, ctx));
1053
+ mergedPerm.collection()->push_back(Node::createSelector(pMergedWrapper));
1067
1054
  mergedPerm.collection()->push_back(Node::createCombinator(Complex_Selector::ADJACENT_TO));
1068
1055
  newRes.collection()->push_back(mergedPerm);
1069
1056
  }
@@ -1096,7 +1083,7 @@ namespace Sass {
1096
1083
 
1097
1084
  Complex_Selector_Obj pMergedWrapper = SASS_MEMORY_CLONE(sel1.selector()); // Clone the Complex_Selector to get back to something we can transform to a node once we replace the head with the unification result
1098
1085
  // TODO: does subject matter? Ruby: return unless merged = sel1.unify(sel2.members, sel2.subject?)
1099
- Compound_Selector_Ptr pMerged = sel1.selector()->head()->unify_with(&sel2.selector()->head(), ctx);
1086
+ Compound_Selector_Ptr pMerged = sel1.selector()->head()->unify_with(sel2.selector()->head());
1100
1087
  pMergedWrapper->head(pMerged);
1101
1088
 
1102
1089
  DEBUG_EXEC(ALL, printCompoundSelector(pMerged, "MERGED: "))
@@ -1106,7 +1093,7 @@ namespace Sass {
1106
1093
  }
1107
1094
 
1108
1095
  res.collection()->push_front(op1);
1109
- res.collection()->push_front(Node::createSelector(&pMergedWrapper, ctx));
1096
+ res.collection()->push_front(Node::createSelector(pMergedWrapper));
1110
1097
 
1111
1098
  DEBUG_PRINTLN(ALL, "RESULT: " << res)
1112
1099
 
@@ -1114,7 +1101,7 @@ namespace Sass {
1114
1101
  return Node::createNil();
1115
1102
  }
1116
1103
 
1117
- return mergeFinalOps(seq1, seq2, ctx, res);
1104
+ return mergeFinalOps(seq1, seq2, res);
1118
1105
 
1119
1106
  } else if (!ops1.collection()->empty()) {
1120
1107
 
@@ -1129,7 +1116,7 @@ namespace Sass {
1129
1116
  res.collection()->push_front(seq1.collection()->back());
1130
1117
  seq1.collection()->pop_back();
1131
1118
 
1132
- return mergeFinalOps(seq1, seq2, ctx, res);
1119
+ return mergeFinalOps(seq1, seq2, res);
1133
1120
 
1134
1121
  } else { // !ops2.collection()->empty()
1135
1122
 
@@ -1143,7 +1130,7 @@ namespace Sass {
1143
1130
  res.collection()->push_front(seq2.collection()->back());
1144
1131
  seq2.collection()->pop_back();
1145
1132
 
1146
- return mergeFinalOps(seq1, seq2, ctx, res);
1133
+ return mergeFinalOps(seq1, seq2, res);
1147
1134
 
1148
1135
  }
1149
1136
 
@@ -1186,7 +1173,7 @@ namespace Sass {
1186
1173
  result
1187
1174
  end
1188
1175
  */
1189
- Node Extend::subweave(Node& one, Node& two, Context& ctx) {
1176
+ Node subweave(Node& one, Node& two) {
1190
1177
  // Check for the simple cases
1191
1178
  if (one.collection()->size() == 0) {
1192
1179
  Node out = Node::createCollection();
@@ -1199,8 +1186,6 @@ namespace Sass {
1199
1186
  return out;
1200
1187
  }
1201
1188
 
1202
-
1203
-
1204
1189
  Node seq1 = Node::createCollection();
1205
1190
  seq1.plus(one);
1206
1191
  Node seq2 = Node::createCollection();
@@ -1209,7 +1194,7 @@ namespace Sass {
1209
1194
  DEBUG_PRINTLN(SUBWEAVE, "SUBWEAVE ONE: " << seq1)
1210
1195
  DEBUG_PRINTLN(SUBWEAVE, "SUBWEAVE TWO: " << seq2)
1211
1196
 
1212
- Node init = mergeInitialOps(seq1, seq2, ctx);
1197
+ Node init = mergeInitialOps(seq1, seq2);
1213
1198
  if (init.isNil()) {
1214
1199
  return Node::createNil();
1215
1200
  }
@@ -1217,7 +1202,7 @@ namespace Sass {
1217
1202
  DEBUG_PRINTLN(SUBWEAVE, "INIT: " << init)
1218
1203
 
1219
1204
  Node res = Node::createCollection();
1220
- Node fin = mergeFinalOps(seq1, seq2, ctx, res);
1205
+ Node fin = mergeFinalOps(seq1, seq2, res);
1221
1206
  if (fin.isNil()) {
1222
1207
  return Node::createNil();
1223
1208
  }
@@ -1245,23 +1230,23 @@ namespace Sass {
1245
1230
 
1246
1231
 
1247
1232
 
1248
- Node groupSeq1 = groupSelectors(seq1, ctx);
1233
+ Node groupSeq1 = groupSelectors(seq1);
1249
1234
  DEBUG_PRINTLN(SUBWEAVE, "SEQ1: " << groupSeq1)
1250
1235
 
1251
- Node groupSeq2 = groupSelectors(seq2, ctx);
1236
+ Node groupSeq2 = groupSelectors(seq2);
1252
1237
  DEBUG_PRINTLN(SUBWEAVE, "SEQ2: " << groupSeq2)
1253
1238
 
1254
1239
 
1255
1240
  ComplexSelectorDeque groupSeq1Converted;
1256
- nodeToComplexSelectorDeque(groupSeq1, groupSeq1Converted, ctx);
1241
+ nodeToComplexSelectorDeque(groupSeq1, groupSeq1Converted);
1257
1242
 
1258
1243
  ComplexSelectorDeque groupSeq2Converted;
1259
- nodeToComplexSelectorDeque(groupSeq2, groupSeq2Converted, ctx);
1244
+ nodeToComplexSelectorDeque(groupSeq2, groupSeq2Converted);
1260
1245
 
1261
1246
  ComplexSelectorDeque out;
1262
- LcsCollectionComparator collectionComparator(ctx);
1263
- lcs(groupSeq2Converted, groupSeq1Converted, collectionComparator, ctx, out);
1264
- Node seqLcs = complexSelectorDequeToNode(out, ctx);
1247
+ LcsCollectionComparator collectionComparator;
1248
+ lcs(groupSeq2Converted, groupSeq1Converted, collectionComparator, out);
1249
+ Node seqLcs = complexSelectorDequeToNode(out);
1265
1250
 
1266
1251
  DEBUG_PRINTLN(SUBWEAVE, "SEQLCS: " << seqLcs)
1267
1252
 
@@ -1275,7 +1260,7 @@ namespace Sass {
1275
1260
 
1276
1261
 
1277
1262
  while (!seqLcs.collection()->empty()) {
1278
- ParentSuperselectorChunker superselectorChunker(seqLcs, ctx);
1263
+ ParentSuperselectorChunker superselectorChunker(seqLcs);
1279
1264
  Node chunksResult = chunks(groupSeq1, groupSeq2, superselectorChunker);
1280
1265
  diff.collection()->push_back(chunksResult);
1281
1266
 
@@ -1320,7 +1305,7 @@ namespace Sass {
1320
1305
  DEBUG_PRINTLN(SUBWEAVE, "DIFF POST REJECT: " << diff)
1321
1306
 
1322
1307
 
1323
- Node pathsResult = paths(diff, ctx);
1308
+ Node pathsResult = paths(diff);
1324
1309
 
1325
1310
  DEBUG_PRINTLN(SUBWEAVE, "PATHS: " << pathsResult)
1326
1311
 
@@ -1330,7 +1315,7 @@ namespace Sass {
1330
1315
  pathsIter != pathsEndIter; ++pathsIter) {
1331
1316
 
1332
1317
  Node& child = *pathsIter;
1333
- child = flatten(child, ctx);
1318
+ child = flatten(child);
1334
1319
  }
1335
1320
 
1336
1321
  DEBUG_PRINTLN(SUBWEAVE, "FLATTENED: " << pathsResult)
@@ -1348,25 +1333,25 @@ namespace Sass {
1348
1333
  }
1349
1334
  /*
1350
1335
  // disabled to avoid clang warning [-Wunused-function]
1351
- static Node subweaveNaive(const Node& one, const Node& two, Context& ctx) {
1336
+ static Node subweaveNaive(const Node& one, const Node& two) {
1352
1337
  Node out = Node::createCollection();
1353
1338
 
1354
1339
  // Check for the simple cases
1355
1340
  if (one.isNil()) {
1356
- out.collection()->push_back(two.klone(ctx));
1341
+ out.collection()->push_back(two.klone());
1357
1342
  } else if (two.isNil()) {
1358
- out.collection()->push_back(one.klone(ctx));
1343
+ out.collection()->push_back(one.klone());
1359
1344
  } else {
1360
1345
  // Do the naive implementation. pOne = A B and pTwo = C D ...yields... A B C D and C D A B
1361
1346
  // See https://gist.github.com/nex3/7609394 for details.
1362
1347
 
1363
- Node firstPerm = one.klone(ctx);
1364
- Node twoCloned = two.klone(ctx);
1348
+ Node firstPerm = one.klone();
1349
+ Node twoCloned = two.klone();
1365
1350
  firstPerm.plus(twoCloned);
1366
1351
  out.collection()->push_back(firstPerm);
1367
1352
 
1368
- Node secondPerm = two.klone(ctx);
1369
- Node oneCloned = one.klone(ctx);
1353
+ Node secondPerm = two.klone();
1354
+ Node oneCloned = one.klone();
1370
1355
  secondPerm.plus(oneCloned );
1371
1356
  out.collection()->push_back(secondPerm);
1372
1357
  }
@@ -1449,7 +1434,7 @@ namespace Sass {
1449
1434
  return befores
1450
1435
  end
1451
1436
  */
1452
- static Node weave(Node& path, Context& ctx) {
1437
+ Node Extend::weave(Node& path) {
1453
1438
 
1454
1439
  DEBUG_PRINTLN(WEAVE, "WEAVE: " << path)
1455
1440
 
@@ -1460,7 +1445,7 @@ namespace Sass {
1460
1445
  afters.plus(path);
1461
1446
 
1462
1447
  while (!afters.collection()->empty()) {
1463
- Node current = afters.collection()->front().klone(ctx);
1448
+ Node current = afters.collection()->front().klone();
1464
1449
  afters.collection()->pop_front();
1465
1450
  DEBUG_PRINTLN(WEAVE, "CURRENT: " << current)
1466
1451
  if (current.collection()->size() == 0) continue;
@@ -1476,7 +1461,7 @@ namespace Sass {
1476
1461
  for (NodeDeque::iterator beforesIter = befores.collection()->begin(), beforesEndIter = befores.collection()->end(); beforesIter != beforesEndIter; beforesIter++) {
1477
1462
  Node& before = *beforesIter;
1478
1463
 
1479
- Node sub = Extend::subweave(before, current, ctx);
1464
+ Node sub = subweave(before, current);
1480
1465
 
1481
1466
  DEBUG_PRINTLN(WEAVE, "SUB: " << sub)
1482
1467
 
@@ -1491,6 +1476,13 @@ namespace Sass {
1491
1476
  toPush.plus(seqs);
1492
1477
  toPush.plus(last_current);
1493
1478
 
1479
+ // move line feed from inner to outer selector (very hacky indeed)
1480
+ if (last_current.collection() && last_current.collection()->front().selector()) {
1481
+ toPush.got_line_feed = last_current.collection()->front().got_line_feed;
1482
+ last_current.collection()->front().selector()->has_line_feed(false);
1483
+ last_current.collection()->front().got_line_feed = false;
1484
+ }
1485
+
1494
1486
  tempResult.collection()->push_back(toPush);
1495
1487
 
1496
1488
  }
@@ -1505,16 +1497,6 @@ namespace Sass {
1505
1497
 
1506
1498
 
1507
1499
 
1508
- // This forward declaration is needed since extendComplexSelector calls extendCompoundSelector, which may recursively
1509
- // call extendComplexSelector again.
1510
- static Node extendComplexSelector(
1511
- Complex_Selector_Ptr pComplexSelector,
1512
- Context& ctx,
1513
- Subset_Map& subset_map,
1514
- std::set<Compound_Selector> seen, bool isReplace, bool isOriginal);
1515
-
1516
-
1517
-
1518
1500
  /*
1519
1501
  This is the equivalent of ruby's SimpleSequence.do_extend.
1520
1502
 
@@ -1530,65 +1512,60 @@ namespace Sass {
1530
1512
  template<typename KeyType>
1531
1513
  class GroupByToAFunctor {
1532
1514
  public:
1533
- KeyType operator()(ExtensionPair& extPair) const {
1515
+ KeyType operator()(SubSetMapPair& extPair) const {
1534
1516
  Complex_Selector_Obj pSelector = extPair.first;
1535
- return &pSelector;
1517
+ return pSelector;
1536
1518
  }
1537
1519
  };
1538
- static Node extendCompoundSelector(
1539
- Compound_Selector_Ptr pSelector,
1540
- Context& ctx,
1541
- Subset_Map& subset_map,
1542
- std::set<Compound_Selector> seen, bool isReplace) {
1520
+ Node Extend::extendCompoundSelector(Compound_Selector_Ptr pSelector, CompoundSelectorSet& seen, bool isReplace) {
1521
+
1522
+ /* this turned out to be too much overhead
1523
+ probably due to holding a "Node" object
1524
+ // check if we already extended this selector
1525
+ // we can do this since subset_map is "static"
1526
+ auto memoized = memoizeCompound.find(pSelector);
1527
+ if (memoized != memoizeCompound.end()) {
1528
+ return memoized->second.klone();
1529
+ }
1530
+ */
1543
1531
 
1544
1532
  DEBUG_EXEC(EXTEND_COMPOUND, printCompoundSelector(pSelector, "EXTEND COMPOUND: "))
1545
1533
  // TODO: Ruby has another loop here to skip certain members?
1546
1534
 
1547
- Node extendedSelectors = Node::createCollection();
1535
+ // let RESULTS be an empty list of complex selectors
1536
+ Node results = Node::createCollection();
1548
1537
  // extendedSelectors.got_line_feed = true;
1549
1538
 
1550
- SubsetMapEntries entries = subset_map.get_v(pSelector);
1551
-
1552
- typedef std::vector<std::pair<Complex_Selector_Obj, std::vector<ExtensionPair> > > GroupedByToAResult;
1539
+ SubSetMapPairs entries = subset_map.get_v(pSelector);
1553
1540
 
1554
1541
  GroupByToAFunctor<Complex_Selector_Obj> extPairKeyFunctor;
1555
- GroupedByToAResult arr;
1542
+ SubSetMapResults arr;
1556
1543
  group_by_to_a(entries, extPairKeyFunctor, arr);
1557
1544
 
1558
- typedef std::pair<Compound_Selector_Obj, Complex_Selector_Obj> SelsNewSeqPair;
1559
- typedef std::vector<SelsNewSeqPair> SelsNewSeqPairCollection;
1560
-
1545
+ SubSetMapLookups holder;
1561
1546
 
1562
- SelsNewSeqPairCollection holder;
1563
-
1564
-
1565
- for (GroupedByToAResult::iterator groupedIter = arr.begin(), groupedIterEnd = arr.end(); groupedIter != groupedIterEnd; groupedIter++) {
1566
- std::pair<Complex_Selector_Obj, std::vector<ExtensionPair> >& groupedPair = *groupedIter;
1547
+ // for each (EXTENDER, TARGET) in MAP.get(COMPOUND):
1548
+ for (SubSetMapResult& groupedPair : arr) {
1567
1549
 
1568
1550
  Complex_Selector_Obj seq = groupedPair.first;
1569
- std::vector<ExtensionPair>& group = groupedPair.second;
1551
+ SubSetMapPairs& group = groupedPair.second;
1570
1552
 
1571
- DEBUG_EXEC(EXTEND_COMPOUND, printComplexSelector(&seq, "SEQ: "))
1553
+ DEBUG_EXEC(EXTEND_COMPOUND, printComplexSelector(seq, "SEQ: "))
1572
1554
 
1573
- // changing this makes aua
1574
1555
  Compound_Selector_Obj pSels = SASS_MEMORY_NEW(Compound_Selector, pSelector->pstate());
1575
- for (std::vector<ExtensionPair>::iterator groupIter = group.begin(), groupIterEnd = group.end(); groupIter != groupIterEnd; groupIter++) {
1576
- ExtensionPair& pair = *groupIter;
1577
- Compound_Selector_Obj pCompound = pair.second;
1578
- for (size_t index = 0; index < pCompound->length(); index++) {
1579
- Simple_Selector_Obj pSimpleSelector = (*pCompound)[index];
1580
- pSels->append(&pSimpleSelector);
1581
- pCompound->extended(true);
1582
- }
1556
+ for (SubSetMapPair& pair : group) {
1557
+ pair.second->extended(true);
1558
+ pSels->concat(pair.second);
1583
1559
  }
1584
1560
 
1585
- DEBUG_EXEC(EXTEND_COMPOUND, printCompoundSelector(&pSels, "SELS: "))
1561
+ DEBUG_EXEC(EXTEND_COMPOUND, printCompoundSelector(pSels, "SELS: "))
1586
1562
 
1587
- Complex_Selector_Ptr pExtComplexSelector = &seq; // The selector up to where the @extend is (ie, the thing to merge)
1563
+ // The selector up to where the @extend is (ie, the thing to merge)
1564
+ Complex_Selector_Ptr pExtComplexSelector = seq;
1588
1565
 
1589
1566
  // TODO: This can return a Compound_Selector with no elements. Should that just be returning NULL?
1590
1567
  // RUBY: self_without_sel = Sass::Util.array_minus(members, sels)
1591
- Compound_Selector_Obj pSelectorWithoutExtendSelectors = pSelector->minus(&pSels, ctx);
1568
+ Compound_Selector_Obj pSelectorWithoutExtendSelectors = pSelector->minus(pSels);
1592
1569
 
1593
1570
  DEBUG_EXEC(EXTEND_COMPOUND, printCompoundSelector(pSelector, "MEMBERS: "))
1594
1571
  DEBUG_EXEC(EXTEND_COMPOUND, printCompoundSelector(pSelectorWithoutExtendSelectors, "SELF_WO_SEL: "))
@@ -1598,7 +1575,7 @@ namespace Sass {
1598
1575
  if (!pInnermostCompoundSelector) {
1599
1576
  pInnermostCompoundSelector = SASS_MEMORY_NEW(Compound_Selector, pSelector->pstate());
1600
1577
  }
1601
- Compound_Selector_Obj pUnifiedSelector = pInnermostCompoundSelector->unify_with(&pSelectorWithoutExtendSelectors, ctx);
1578
+ Compound_Selector_Obj pUnifiedSelector = pInnermostCompoundSelector->unify_with(pSelectorWithoutExtendSelectors);
1602
1579
 
1603
1580
  DEBUG_EXEC(EXTEND_COMPOUND, printCompoundSelector(pInnermostCompoundSelector, "LHS: "))
1604
1581
  DEBUG_EXEC(EXTEND_COMPOUND, printCompoundSelector(pSelectorWithoutExtendSelectors, "RHS: "))
@@ -1621,10 +1598,10 @@ namespace Sass {
1621
1598
  Complex_Selector_Obj pNewInnerMost = SASS_MEMORY_NEW(Complex_Selector, pSelector->pstate(), Complex_Selector::ANCESTOR_OF, pUnifiedSelector, NULL);
1622
1599
 
1623
1600
  Complex_Selector::Combinator combinator = pNewSelector->clear_innermost();
1624
- pNewSelector->set_innermost(&pNewInnerMost, combinator);
1601
+ pNewSelector->set_innermost(pNewInnerMost, combinator);
1625
1602
 
1626
1603
  #ifdef DEBUG
1627
- SourcesSet debugSet;
1604
+ ComplexSelectorSet debugSet;
1628
1605
  debugSet = pNewSelector->sources();
1629
1606
  if (debugSet.size() > 0) {
1630
1607
  throw std::runtime_error("The new selector should start with no sources. Something needs to be cloned to fix this.");
@@ -1638,21 +1615,22 @@ namespace Sass {
1638
1615
 
1639
1616
  // if (pSelector && pSelector->has_line_feed()) pNewInnerMost->has_line_feed(true);
1640
1617
  // Set the sources on our new Complex_Selector to the sources of this simple sequence plus the thing we're extending.
1641
- DEBUG_PRINTLN(EXTEND_COMPOUND, "SOURCES SETTING ON NEW SEQ: " << complexSelectorToNode(pNewSelector, ctx))
1618
+ DEBUG_PRINTLN(EXTEND_COMPOUND, "SOURCES SETTING ON NEW SEQ: " << complexSelectorToNode(pNewSelector))
1642
1619
 
1643
- DEBUG_EXEC(EXTEND_COMPOUND, SourcesSet oldSet = pNewSelector->sources(); printSourcesSet(oldSet, ctx, "SOURCES NEW SEQ BEGIN: "))
1620
+ DEBUG_EXEC(EXTEND_COMPOUND, ComplexSelectorSet oldSet = pNewSelector->sources(); printSourcesSet(oldSet, "SOURCES NEW SEQ BEGIN: "))
1644
1621
 
1645
- SourcesSet newSourcesSet = pSelector->sources();
1646
- DEBUG_EXEC(EXTEND_COMPOUND, printSourcesSet(newSourcesSet, ctx, "SOURCES THIS EXTEND: "))
1622
+ // I actually want to create a copy here (performance!)
1623
+ ComplexSelectorSet newSourcesSet = pSelector->sources(); // XXX
1624
+ DEBUG_EXEC(EXTEND_COMPOUND, printSourcesSet(newSourcesSet, "SOURCES THIS EXTEND: "))
1647
1625
 
1648
1626
  newSourcesSet.insert(pExtComplexSelector);
1649
- DEBUG_EXEC(EXTEND_COMPOUND, printSourcesSet(newSourcesSet, ctx, "SOURCES WITH NEW SOURCE: "))
1627
+ DEBUG_EXEC(EXTEND_COMPOUND, printSourcesSet(newSourcesSet, "SOURCES WITH NEW SOURCE: "))
1650
1628
 
1651
1629
  // RUBY: new_seq.add_sources!(sources + [seq])
1652
- pNewSelector->addSources(newSourcesSet, ctx);
1630
+ pNewSelector->addSources(newSourcesSet);
1653
1631
 
1654
- DEBUG_EXEC(EXTEND_COMPOUND, SourcesSet newSet = pNewSelector->sources(); printSourcesSet(newSet, ctx, "SOURCES ON NEW SELECTOR AFTER ADD: "))
1655
- DEBUG_EXEC(EXTEND_COMPOUND, printSourcesSet(pSelector->sources(), ctx, "SOURCES THIS EXTEND WHICH SHOULD BE SAME STILL: "))
1632
+ DEBUG_EXEC(EXTEND_COMPOUND, ComplexSelectorSet newSet = pNewSelector->sources(); printSourcesSet(newSet, "SOURCES ON NEW SELECTOR AFTER ADD: "))
1633
+ DEBUG_EXEC(EXTEND_COMPOUND, printSourcesSet(pSelector->sources(), "SOURCES THIS EXTEND WHICH SHOULD BE SAME STILL: "))
1656
1634
 
1657
1635
 
1658
1636
  if (pSels->has_line_feed()) pNewSelector->has_line_feed(true);
@@ -1661,25 +1639,24 @@ namespace Sass {
1661
1639
  }
1662
1640
 
1663
1641
 
1664
- for (SelsNewSeqPairCollection::iterator holderIter = holder.begin(), holderIterEnd = holder.end(); holderIter != holderIterEnd; holderIter++) {
1665
- SelsNewSeqPair& pair = *holderIter;
1642
+ for (SubSetMapLookup& pair : holder) {
1666
1643
 
1667
1644
  Compound_Selector_Obj pSels = pair.first;
1668
1645
  Complex_Selector_Obj pNewSelector = pair.second;
1669
1646
 
1670
1647
 
1671
1648
  // RUBY??: next [] if seen.include?(sels)
1672
- if (seen.find(*pSels) != seen.end()) {
1649
+ if (seen.find(pSels) != seen.end()) {
1673
1650
  continue;
1674
1651
  }
1675
1652
 
1676
1653
 
1677
- std::set<Compound_Selector> recurseSeen(seen);
1678
- recurseSeen.insert(*pSels);
1654
+ CompoundSelectorSet recurseSeen(seen);
1655
+ recurseSeen.insert(pSels);
1679
1656
 
1680
1657
 
1681
- DEBUG_PRINTLN(EXTEND_COMPOUND, "RECURSING DO EXTEND: " << complexSelectorToNode(pNewSelector, ctx))
1682
- Node recurseExtendedSelectors = extendComplexSelector(&pNewSelector, ctx, subset_map, recurseSeen, isReplace, false); // !:isOriginal
1658
+ DEBUG_PRINTLN(EXTEND_COMPOUND, "RECURSING DO EXTEND: " << complexSelectorToNode(pNewSelector))
1659
+ Node recurseExtendedSelectors = extendComplexSelector(pNewSelector, recurseSeen, isReplace, false); // !:isOriginal
1683
1660
 
1684
1661
  DEBUG_PRINTLN(EXTEND_COMPOUND, "RECURSING DO EXTEND RETURN: " << recurseExtendedSelectors)
1685
1662
 
@@ -1687,38 +1664,39 @@ namespace Sass {
1687
1664
  iterator != endIterator; ++iterator) {
1688
1665
  Node newSelector = *iterator;
1689
1666
 
1690
- // DEBUG_PRINTLN(EXTEND_COMPOUND, "EXTENDED AT THIS POINT: " << extendedSelectors)
1691
- // DEBUG_PRINTLN(EXTEND_COMPOUND, "SELECTOR EXISTS ALREADY: " << newSelector << " " << extendedSelectors.contains(newSelector, false /*simpleSelectorOrderDependent*/));
1667
+ // DEBUG_PRINTLN(EXTEND_COMPOUND, "EXTENDED AT THIS POINT: " << results)
1668
+ // DEBUG_PRINTLN(EXTEND_COMPOUND, "SELECTOR EXISTS ALREADY: " << newSelector << " " << results.contains(newSelector, false /*simpleSelectorOrderDependent*/));
1692
1669
 
1693
- if (!extendedSelectors.contains(newSelector, false /*simpleSelectorOrderDependent*/)) {
1670
+ if (!results.contains(newSelector)) {
1694
1671
  // DEBUG_PRINTLN(EXTEND_COMPOUND, "ADDING NEW SELECTOR")
1695
- extendedSelectors.collection()->push_back(newSelector);
1672
+ results.collection()->push_back(newSelector);
1696
1673
  }
1697
1674
  }
1698
1675
  }
1699
1676
 
1700
1677
  DEBUG_EXEC(EXTEND_COMPOUND, printCompoundSelector(pSelector, "EXTEND COMPOUND END: "))
1701
1678
 
1702
- return extendedSelectors;
1679
+ // this turned out to be too much overhead
1680
+ // memory results in a map table - since extending is very expensive
1681
+ // memoizeCompound.insert(std::pair<Compound_Selector_Obj, Node>(pSelector, results));
1682
+
1683
+ return results;
1703
1684
  }
1704
1685
 
1705
1686
 
1706
- static bool complexSelectorHasExtension(
1707
- Complex_Selector_Ptr pComplexSelector,
1708
- Context& ctx,
1709
- Subset_Map& subset_map,
1710
- std::set<Compound_Selector>& seen) {
1687
+ // check if selector has something to be extended by subset_map
1688
+ bool Extend::complexSelectorHasExtension(Complex_Selector_Ptr selector, CompoundSelectorSet& seen) {
1711
1689
 
1712
1690
  bool hasExtension = false;
1713
1691
 
1714
- Complex_Selector_Obj pIter = pComplexSelector;
1692
+ Complex_Selector_Obj pIter = selector;
1715
1693
 
1716
1694
  while (!hasExtension && pIter) {
1717
1695
  Compound_Selector_Obj pHead = pIter->head();
1718
1696
 
1719
1697
  if (pHead) {
1720
- SubsetMapEntries entries = subset_map.get_v(pHead);
1721
- for (ExtensionPair ext : entries) {
1698
+ SubSetMapPairs entries = subset_map.get_v(pHead);
1699
+ for (SubSetMapPair ext : entries) {
1722
1700
  // check if both selectors have the same media block parent
1723
1701
  // if (ext.first->media_block() == pComplexSelector->media_block()) continue;
1724
1702
  if (ext.second->media_block() == 0) continue;
@@ -1726,8 +1704,8 @@ namespace Sass {
1726
1704
  ext.second->media_block()->media_queries() &&
1727
1705
  pHead->media_block()->media_queries()
1728
1706
  ) {
1729
- std::string query_left(ext.second->media_block()->media_queries()->to_string(ctx.c_options));
1730
- std::string query_right(pHead->media_block()->media_queries()->to_string(ctx.c_options));
1707
+ std::string query_left(ext.second->media_block()->media_queries()->to_string());
1708
+ std::string query_right(pHead->media_block()->media_queries()->to_string());
1731
1709
  if (query_left == query_right) continue;
1732
1710
  }
1733
1711
 
@@ -1738,9 +1716,9 @@ namespace Sass {
1738
1716
  std::string rel_path(Sass::File::abs2rel(pstate.path, cwd, cwd));
1739
1717
  err << "You may not @extend an outer selector from within @media.\n";
1740
1718
  err << "You may only @extend selectors within the same directive.\n";
1741
- err << "From \"@extend " << ext.second->to_string(ctx.c_options) << "\"";
1719
+ err << "From \"@extend " << ext.second->to_string() << "\"";
1742
1720
  err << " on line " << pstate.line+1 << " of " << rel_path << "\n";
1743
- error(err.str(), pComplexSelector->pstate());
1721
+ error(err.str(), selector->pstate(), eval->exp.traces);
1744
1722
  }
1745
1723
  if (entries.size() > 0) hasExtension = true;
1746
1724
  }
@@ -1763,23 +1741,25 @@ namespace Sass {
1763
1741
  the combinator and compound selector are one unit
1764
1742
  next [[sseq_or_op]] unless sseq_or_op.is_a?(SimpleSequence)
1765
1743
  */
1766
- static Node extendComplexSelector(
1767
- Complex_Selector_Ptr pComplexSelector,
1768
- Context& ctx,
1769
- Subset_Map& subset_map,
1770
- std::set<Compound_Selector> seen, bool isReplace, bool isOriginal) {
1744
+ Node Extend::extendComplexSelector(Complex_Selector_Ptr selector, CompoundSelectorSet& seen, bool isReplace, bool isOriginal) {
1771
1745
 
1772
- Node complexSelector = complexSelectorToNode(pComplexSelector, ctx);
1773
- DEBUG_PRINTLN(EXTEND_COMPLEX, "EXTEND COMPLEX: " << complexSelector)
1746
+ // check if we already extended this selector
1747
+ // we can do this since subset_map is "static"
1748
+ auto memoized = memoizeComplex.find(selector);
1749
+ if (memoized != memoizeComplex.end()) {
1750
+ return memoized->second;
1751
+ }
1774
1752
 
1775
- Node extendedNotExpanded = Node::createCollection();
1753
+ // convert the input selector to extend node format
1754
+ Node complexSelector = complexSelectorToNode(selector);
1755
+ DEBUG_PRINTLN(EXTEND_COMPLEX, "EXTEND COMPLEX: " << complexSelector)
1776
1756
 
1777
- for (NodeDeque::iterator complexSelIter = complexSelector.collection()->begin(),
1778
- complexSelIterEnd = complexSelector.collection()->end();
1779
- complexSelIter != complexSelIterEnd; ++complexSelIter)
1780
- {
1757
+ // let CHOICES be an empty list of selector-lists
1758
+ // create new collection to hold the results
1759
+ Node choices = Node::createCollection();
1781
1760
 
1782
- Node& sseqOrOp = *complexSelIter;
1761
+ // for each compound selector COMPOUND in COMPLEX:
1762
+ for (Node& sseqOrOp : *complexSelector.collection()) {
1783
1763
 
1784
1764
  DEBUG_PRINTLN(EXTEND_COMPLEX, "LOOP: " << sseqOrOp)
1785
1765
 
@@ -1792,94 +1772,93 @@ namespace Sass {
1792
1772
  Node inner = Node::createCollection();
1793
1773
  outer.collection()->push_back(inner);
1794
1774
  inner.collection()->push_back(sseqOrOp);
1795
- extendedNotExpanded.collection()->push_back(outer);
1775
+ choices.collection()->push_back(outer);
1796
1776
  continue;
1797
1777
  }
1798
1778
 
1799
- Compound_Selector_Obj pCompoundSelector = sseqOrOp.selector()->head();
1779
+ // verified now that node is a valid selector
1780
+ Complex_Selector_Obj sseqSel = sseqOrOp.selector();
1781
+ Compound_Selector_Obj sseqHead = sseqSel->head();
1800
1782
 
1783
+ // let EXTENDED be extend_compound(COMPOUND, SEEN)
1784
+ // extend the compound selector against the given subset_map
1801
1785
  // RUBY: extended = sseq_or_op.do_extend(extends, parent_directives, replace, seen)
1802
- Node extended = extendCompoundSelector(&pCompoundSelector, ctx, subset_map, seen, isReplace);
1786
+ Node extended = extendCompoundSelector(sseqHead, seen, isReplace); // slow(17%)!
1803
1787
  if (sseqOrOp.got_line_feed) extended.got_line_feed = true;
1804
1788
  DEBUG_PRINTLN(EXTEND_COMPLEX, "EXTENDED: " << extended)
1805
1789
 
1806
-
1807
- // Prepend the Compound_Selector based on the choices logic; choices seems to be extend but with an ruby Array instead of a Sequence
1808
- // due to the member mapping: choices = extended.map {|seq| seq.members}
1809
- Complex_Selector_Obj pJustCurrentCompoundSelector = sseqOrOp.selector();
1810
-
1790
+ // Prepend the Compound_Selector based on the choices logic; choices seems to be extend but with a ruby
1791
+ // Array instead of a Sequence due to the member mapping: choices = extended.map {|seq| seq.members}
1811
1792
  // RUBY: extended.first.add_sources!([self]) if original && !has_placeholder?
1812
- if (isOriginal && !pComplexSelector->has_placeholder()) {
1813
- SourcesSet srcset;
1814
- srcset.insert(pComplexSelector);
1815
- pJustCurrentCompoundSelector->addSources(srcset, ctx);
1816
- DEBUG_PRINTLN(EXTEND_COMPLEX, "ADD SOURCES: " << *pComplexSelector)
1793
+ if (isOriginal && !selector->has_placeholder()) {
1794
+ ComplexSelectorSet srcset;
1795
+ srcset.insert(selector);
1796
+ sseqSel->addSources(srcset);
1797
+ // DEBUG_PRINTLN(EXTEND_COMPLEX, "ADD SOURCES: " << *pComplexSelector)
1817
1798
  }
1818
1799
 
1819
1800
  bool isSuperselector = false;
1820
- for (NodeDeque::iterator iterator = extended.collection()->begin(), endIterator = extended.collection()->end();
1821
- iterator != endIterator; ++iterator) {
1822
- Node& childNode = *iterator;
1823
- Complex_Selector_Obj pExtensionSelector = nodeToComplexSelector(childNode, ctx);
1824
- if (pExtensionSelector->is_superselector_of(pJustCurrentCompoundSelector)) {
1801
+ // if no complex selector in EXTENDED is a superselector of COMPOUND:
1802
+ for (Node& childNode : *extended.collection()) {
1803
+ Complex_Selector_Obj pExtensionSelector = nodeToComplexSelector(childNode);
1804
+ if (pExtensionSelector->is_superselector_of(sseqSel)) {
1825
1805
  isSuperselector = true;
1826
1806
  break;
1827
1807
  }
1828
1808
  }
1829
1809
 
1830
1810
  if (!isSuperselector) {
1831
- if (sseqOrOp.got_line_feed) pJustCurrentCompoundSelector->has_line_feed(sseqOrOp.got_line_feed);
1832
- extended.collection()->push_front(complexSelectorToNode(&pJustCurrentCompoundSelector, ctx));
1811
+ // add a complex selector composed only of COMPOUND to EXTENDED
1812
+ if (sseqOrOp.got_line_feed) sseqSel->has_line_feed(sseqOrOp.got_line_feed);
1813
+ extended.collection()->push_front(complexSelectorToNode(sseqSel));
1833
1814
  }
1834
1815
 
1835
1816
  DEBUG_PRINTLN(EXTEND_COMPLEX, "CHOICES UNSHIFTED: " << extended)
1836
1817
 
1818
+ // add EXTENDED to CHOICES
1837
1819
  // Aggregate our current extensions
1838
- extendedNotExpanded.collection()->push_back(extended);
1820
+ choices.collection()->push_back(extended);
1839
1821
  }
1840
1822
 
1841
1823
 
1842
- DEBUG_PRINTLN(EXTEND_COMPLEX, "EXTENDED NOT EXPANDED: " << extendedNotExpanded)
1824
+ DEBUG_PRINTLN(EXTEND_COMPLEX, "EXTENDED NOT EXPANDED: " << choices)
1843
1825
 
1844
1826
 
1845
1827
 
1846
1828
  // Ruby Equivalent: paths
1847
- Node paths = Sass::paths(extendedNotExpanded, ctx);
1829
+ Node paths = Sass::paths(choices);
1848
1830
 
1849
1831
  DEBUG_PRINTLN(EXTEND_COMPLEX, "PATHS: " << paths)
1850
1832
 
1851
-
1852
-
1853
- // Ruby Equivalent: weave
1833
+ // let WEAVES be an empty list of selector lists
1854
1834
  Node weaves = Node::createCollection();
1855
1835
 
1856
- for (NodeDeque::iterator pathsIter = paths.collection()->begin(), pathsEndIter = paths.collection()->end(); pathsIter != pathsEndIter; ++pathsIter) {
1857
- Node& path = *pathsIter;
1858
- Node weaved = weave(path, ctx);
1836
+ // for each list of complex selectors PATH in paths(CHOICES):
1837
+ for (Node& path : *paths.collection()) {
1838
+ // add weave(PATH) to WEAVES
1839
+ Node weaved = weave(path); // slow(12%)!
1859
1840
  weaved.got_line_feed = path.got_line_feed;
1860
1841
  weaves.collection()->push_back(weaved);
1861
1842
  }
1862
1843
 
1863
1844
  DEBUG_PRINTLN(EXTEND_COMPLEX, "WEAVES: " << weaves)
1864
1845
 
1865
-
1866
-
1867
1846
  // Ruby Equivalent: trim
1868
- Node trimmed = trim(weaves, ctx, isReplace);
1847
+ Node trimmed(trim(weaves, isReplace)); // slow(19%)!
1869
1848
 
1870
1849
  DEBUG_PRINTLN(EXTEND_COMPLEX, "TRIMMED: " << trimmed)
1871
1850
 
1872
-
1873
1851
  // Ruby Equivalent: flatten
1874
- Node extendedSelectors = flatten(trimmed, ctx, 1);
1852
+ Node flattened(flatten(trimmed, 1));
1875
1853
 
1876
1854
  DEBUG_PRINTLN(EXTEND_COMPLEX, ">>>>> EXTENDED: " << extendedSelectors)
1877
-
1878
-
1879
1855
  DEBUG_PRINTLN(EXTEND_COMPLEX, "EXTEND COMPLEX END: " << complexSelector)
1880
1856
 
1857
+ // memory results in a map table - since extending is very expensive
1858
+ memoizeComplex.insert(std::pair<Complex_Selector_Obj, Node>(selector, flattened));
1881
1859
 
1882
- return extendedSelectors;
1860
+ // return trim(WEAVES)
1861
+ return flattened;
1883
1862
  }
1884
1863
 
1885
1864
 
@@ -1887,20 +1866,23 @@ namespace Sass {
1887
1866
  /*
1888
1867
  This is the equivalent of ruby's CommaSequence.do_extend.
1889
1868
  */
1890
- Selector_List_Ptr Extend::extendSelectorList(Selector_List_Obj pSelectorList, Context& ctx, Subset_Map& subset_map, bool isReplace, bool& extendedSomething) {
1891
- std::set<Compound_Selector> seen;
1892
- return extendSelectorList(pSelectorList, ctx, subset_map, isReplace, extendedSomething, seen);
1893
- }
1894
-
1895
- /*
1896
- This is the equivalent of ruby's CommaSequence.do_extend.
1897
- */
1898
- Selector_List_Ptr Extend::extendSelectorList(Selector_List_Obj pSelectorList, Context& ctx, Subset_Map& subset_map, bool isReplace, bool& extendedSomething, std::set<Compound_Selector>& seen) {
1869
+ // We get a selector list with has something to extend and a subset_map with
1870
+ // all extenders. Pick the ones that match our selectors in the list.
1871
+ Selector_List_Ptr Extend::extendSelectorList(Selector_List_Obj pSelectorList, bool isReplace, bool& extendedSomething, CompoundSelectorSet& seen) {
1899
1872
 
1900
1873
  Selector_List_Obj pNewSelectors = SASS_MEMORY_NEW(Selector_List, pSelectorList->pstate(), pSelectorList->length());
1901
1874
 
1902
- extendedSomething = false;
1875
+ // check if we already extended this selector
1876
+ // we can do this since subset_map is "static"
1877
+ auto memoized = memoizeList.find(pSelectorList);
1878
+ if (memoized != memoizeList.end()) {
1879
+ extendedSomething = true;
1880
+ return memoized->second;
1881
+ }
1903
1882
 
1883
+ extendedSomething = false;
1884
+ // process each comlplex selector in the selector list.
1885
+ // Find the ones that can be extended by given subset_map.
1904
1886
  for (size_t index = 0, length = pSelectorList->length(); index < length; index++) {
1905
1887
  Complex_Selector_Obj pSelector = (*pSelectorList)[index];
1906
1888
 
@@ -1909,89 +1891,100 @@ namespace Sass {
1909
1891
  // run through the extend code (which does a data model transformation), check if there is anything to extend before doing
1910
1892
  // the extend. We might be able to optimize extendComplexSelector, but this approach keeps us closer to ruby sass (which helps
1911
1893
  // when debugging).
1912
- if (!complexSelectorHasExtension(&pSelector, ctx, subset_map, seen)) {
1913
- pNewSelectors->append(&pSelector);
1894
+ if (!complexSelectorHasExtension(pSelector, seen)) {
1895
+ pNewSelectors->append(pSelector);
1914
1896
  continue;
1915
1897
  }
1916
1898
 
1899
+ // complexSelectorHasExtension was true!
1917
1900
  extendedSomething = true;
1918
1901
 
1919
- Node extendedSelectors = extendComplexSelector(&pSelector, ctx, subset_map, seen, isReplace, true);
1902
+ // now do the actual extension of the complex selector
1903
+ Node extendedSelectors = extendComplexSelector(pSelector, seen, isReplace, true);
1904
+
1920
1905
  if (!pSelector->has_placeholder()) {
1921
- if (!extendedSelectors.contains(complexSelectorToNode(&pSelector, ctx), true /*simpleSelectorOrderDependent*/)) {
1906
+ Node nSelector(complexSelectorToNode(pSelector));
1907
+ if (!extendedSelectors.contains(nSelector)) {
1922
1908
  pNewSelectors->append(pSelector);
1923
1909
  continue;
1924
1910
  }
1925
1911
  }
1926
1912
 
1927
- for (NodeDeque::iterator iterator = extendedSelectors.collection()->begin(), iteratorBegin = extendedSelectors.collection()->begin(), iteratorEnd = extendedSelectors.collection()->end(); iterator != iteratorEnd; ++iterator) {
1913
+ bool doReplace = isReplace;
1914
+ for (Node& childNode : *extendedSelectors.collection()) {
1928
1915
  // When it is a replace, skip the first one, unless there is only one
1929
- if(isReplace && iterator == iteratorBegin && extendedSelectors.collection()->size() > 1 ) continue;
1930
-
1931
- Node& childNode = *iterator;
1932
- pNewSelectors->append(nodeToComplexSelector(childNode, ctx));
1916
+ if(doReplace && extendedSelectors.collection()->size() > 1 ) {
1917
+ doReplace = false;
1918
+ continue;
1919
+ }
1920
+ pNewSelectors->append(nodeToComplexSelector(childNode));
1933
1921
  }
1934
1922
  }
1935
1923
 
1936
- Remove_Placeholders remove_placeholders(ctx);
1924
+ Remove_Placeholders remove_placeholders;
1937
1925
  // it seems that we have to remove the place holders early here
1938
1926
  // normally we do this as the very last step (compare to ruby sass)
1939
- pNewSelectors = remove_placeholders.remove_placeholders(&pNewSelectors);
1927
+ pNewSelectors = remove_placeholders.remove_placeholders(pNewSelectors);
1940
1928
 
1941
1929
  // unwrap all wrapped selectors with inner lists
1942
1930
  for (Complex_Selector_Obj cur : pNewSelectors->elements()) {
1943
1931
  // process tails
1944
1932
  while (cur) {
1945
1933
  // process header
1946
- if (cur->head() && seen.find(*cur->head()) == seen.end()) {
1947
- std::set<Compound_Selector> recseen(seen);
1948
- recseen.insert(*cur->head());
1934
+ if (cur->head() && seen.find(cur->head()) == seen.end()) {
1935
+ CompoundSelectorSet recseen(seen);
1936
+ recseen.insert(cur->head());
1949
1937
  // create a copy since we add multiple items if stuff get unwrapped
1950
1938
  Compound_Selector_Obj cpy_head = SASS_MEMORY_NEW(Compound_Selector, cur->pstate());
1951
1939
  for (Simple_Selector_Obj hs : *cur->head()) {
1952
- if (Wrapped_Selector_Obj ws = SASS_MEMORY_CAST(Wrapped_Selector, hs)) {
1940
+ if (Wrapped_Selector_Obj ws = Cast<Wrapped_Selector>(hs)) {
1953
1941
  ws->selector(SASS_MEMORY_CLONE(ws->selector()));
1954
- if (Selector_List_Obj sl = SASS_MEMORY_CAST(Selector_List, ws->selector())) {
1942
+ if (Selector_List_Obj sl = Cast<Selector_List>(ws->selector())) {
1955
1943
  // special case for ruby ass
1956
1944
  if (sl->empty()) {
1957
1945
  // this seems inconsistent but it is how ruby sass seems to remove parentheses
1958
1946
  cpy_head->append(SASS_MEMORY_NEW(Element_Selector, hs->pstate(), ws->name()));
1959
1947
  }
1960
- // has wrapped selectors
1961
- else {
1948
+ // has wrapped not selectors
1949
+ else if (ws->name() == ":not") {
1962
1950
  // extend the inner list of wrapped selector
1963
- Selector_List_Obj ext_sl = extendSelectorList(sl, ctx, subset_map, recseen);
1951
+ bool extended = false;
1952
+ Selector_List_Obj ext_sl = extendSelectorList(sl, false, extended, recseen);
1964
1953
  for (size_t i = 0; i < ext_sl->length(); i += 1) {
1965
1954
  if (Complex_Selector_Obj ext_cs = ext_sl->at(i)) {
1966
1955
  // create clones for wrapped selector and the inner list
1967
- Wrapped_Selector_Obj cpy_ws = SASS_MEMORY_COPY(&ws);
1956
+ Wrapped_Selector_Obj cpy_ws = SASS_MEMORY_COPY(ws);
1968
1957
  Selector_List_Obj cpy_ws_sl = SASS_MEMORY_NEW(Selector_List, sl->pstate());
1969
1958
  // remove parent selectors from inner selector
1970
- if (ext_cs->first() && ext_cs->first()->head()->length() > 0) {
1971
- Wrapped_Selector_Ptr ext_ws = SASS_MEMORY_CAST(Wrapped_Selector, ext_cs->first()->head()->first());
1972
- if (ext_ws/* && ext_cs->length() == 1*/) {
1973
- Selector_List_Obj ws_cs = SASS_MEMORY_CAST(Selector_List, ext_ws->selector());
1974
- Compound_Selector_Obj ws_ss = ws_cs->first()->head();
1975
- if (!(
1976
- SASS_MEMORY_CAST(Pseudo_Selector, ws_ss->first()) ||
1977
- SASS_MEMORY_CAST(Element_Selector, ws_ss->first()) ||
1978
- SASS_MEMORY_CAST(Placeholder_Selector, ws_ss->first())
1979
- )) continue;
1980
- }
1959
+ Compound_Selector_Obj ext_head = NULL;
1960
+ if (ext_cs->first()) ext_head = ext_cs->first()->head();
1961
+ if (ext_head && ext_head && ext_head->length() > 0) {
1981
1962
  cpy_ws_sl->append(ext_cs->first());
1982
1963
  }
1983
1964
  // assign list to clone
1984
- cpy_ws->selector(&cpy_ws_sl);
1965
+ cpy_ws->selector(cpy_ws_sl);
1985
1966
  // append the clone
1986
- cpy_head->append(&cpy_ws);
1967
+ cpy_head->append(cpy_ws);
1987
1968
  }
1988
1969
  }
1970
+ if (eval && extended) {
1971
+ eval->exp.selector_stack.push_back(pNewSelectors);
1972
+ cpy_head->perform(eval);
1973
+ eval->exp.selector_stack.pop_back();
1974
+ }
1975
+ }
1976
+ // has wrapped selectors
1977
+ else {
1978
+ Wrapped_Selector_Obj cpy_ws = SASS_MEMORY_COPY(ws);
1979
+ Selector_List_Obj ext_sl = extendSelectorList(sl, recseen);
1980
+ cpy_ws->selector(ext_sl);
1981
+ cpy_head->append(cpy_ws);
1989
1982
  }
1990
1983
  } else {
1991
- cpy_head->append(&hs);
1984
+ cpy_head->append(hs);
1992
1985
  }
1993
1986
  } else {
1994
- cpy_head->append(&hs);
1987
+ cpy_head->append(hs);
1995
1988
  }
1996
1989
  }
1997
1990
  // replace header
@@ -2001,6 +1994,10 @@ namespace Sass {
2001
1994
  cur = cur->tail();
2002
1995
  }
2003
1996
  }
1997
+
1998
+ // memory results in a map table - since extending is very expensive
1999
+ memoizeList.insert(std::pair<Selector_List_Obj, Selector_List_Obj>(pSelectorList, pNewSelectors));
2000
+
2004
2001
  return pNewSelectors.detach();
2005
2002
 
2006
2003
  }
@@ -2024,8 +2021,9 @@ namespace Sass {
2024
2021
  for (size_t i = 0, L = b->length(); i < L; ++i) {
2025
2022
  Statement_Obj stm = b->at(i);
2026
2023
 
2027
- if (dynamic_cast<Ruleset_Ptr>(&stm)) {
2028
- // Do nothing. This doesn't count as a statement that causes extension since we'll iterate over this rule set in a future visit and try to extend it.
2024
+ if (Cast<Ruleset>(stm)) {
2025
+ // Do nothing. This doesn't count as a statement that causes extension since we'll
2026
+ // iterate over this rule set in a future visit and try to extend it.
2029
2027
  }
2030
2028
  else {
2031
2029
  return true;
@@ -2038,37 +2036,45 @@ namespace Sass {
2038
2036
 
2039
2037
 
2040
2038
  // Extend a ruleset by extending the selectors and updating them on the ruleset. The block's rules don't need to change.
2041
- template <typename ObjectType>
2042
- static void extendObjectWithSelectorAndBlock(ObjectType* pObject, Context& ctx, Subset_Map& subset_map) {
2039
+ // Every Ruleset in the whole tree is calling this function. We decide if there
2040
+ // was is @extend that matches our selector. If we find one, we will go further
2041
+ // and call the extend magic for our selector. The subset_map contains all blocks
2042
+ // where @extend was found. Pick the ones that match our selector!
2043
+ void Extend::extendObjectWithSelectorAndBlock(Ruleset_Ptr pObject) {
2043
2044
 
2044
- DEBUG_PRINTLN(EXTEND_OBJECT, "FOUND SELECTOR: " << static_cast<Selector_List_Ptr>(pObject->selector())->to_string(ctx.c_options))
2045
+ DEBUG_PRINTLN(EXTEND_OBJECT, "FOUND SELECTOR: " << Cast<Selector_List>(pObject->selector())->to_string())
2045
2046
 
2046
- // Ruby sass seems to filter nodes that don't have any content well before we get here. I'm not sure the repercussions
2047
- // of doing so, so for now, let's just not extend things that won't be output later.
2047
+ // Ruby sass seems to filter nodes that don't have any content well before we get here.
2048
+ // I'm not sure the repercussions of doing so, so for now, let's just not extend things
2049
+ // that won't be output later. Profiling shows this may us 0.2% or so.
2048
2050
  if (!shouldExtendBlock(pObject->block())) {
2049
2051
  DEBUG_PRINTLN(EXTEND_OBJECT, "RETURNING WITHOUT EXTEND ATTEMPT")
2050
2052
  return;
2051
2053
  }
2052
2054
 
2053
2055
  bool extendedSomething = false;
2054
- Selector_List_Obj pNewSelectorList = Extend::extendSelectorList(SASS_MEMORY_CAST(Selector_List, pObject->selector()), ctx, subset_map, false, extendedSomething);
2056
+
2057
+ CompoundSelectorSet seen;
2058
+ Selector_List_Obj pNewSelectorList = extendSelectorList(pObject->selector(), false, extendedSomething, seen);
2055
2059
 
2056
2060
  if (extendedSomething && pNewSelectorList) {
2057
- DEBUG_PRINTLN(EXTEND_OBJECT, "EXTEND ORIGINAL SELECTORS: " << static_cast<Selector_List_Ptr>(pObject->selector())->to_string(ctx.c_options))
2058
- DEBUG_PRINTLN(EXTEND_OBJECT, "EXTEND SETTING NEW SELECTORS: " << pNewSelectorList->to_string(ctx.c_options))
2061
+ DEBUG_PRINTLN(EXTEND_OBJECT, "EXTEND ORIGINAL SELECTORS: " << pObject->selector()->to_string())
2062
+ DEBUG_PRINTLN(EXTEND_OBJECT, "EXTEND SETTING NEW SELECTORS: " << pNewSelectorList->to_string())
2059
2063
  pNewSelectorList->remove_parent_selectors();
2060
- pObject->selector(&pNewSelectorList);
2064
+ pObject->selector(pNewSelectorList);
2061
2065
  } else {
2062
2066
  DEBUG_PRINTLN(EXTEND_OBJECT, "EXTEND DID NOT TRY TO EXTEND ANYTHING")
2063
2067
  }
2064
2068
  }
2065
2069
 
2066
-
2067
-
2068
- Extend::Extend(Context& ctx, Subset_Map& ssm)
2069
- : ctx(ctx), subset_map(ssm)
2070
+ Extend::Extend(Subset_Map& ssm)
2071
+ : subset_map(ssm), eval(NULL)
2070
2072
  { }
2071
2073
 
2074
+ void Extend::setEval(Eval& e) {
2075
+ eval = &e;
2076
+ }
2077
+
2072
2078
  void Extend::operator()(Block_Ptr b)
2073
2079
  {
2074
2080
  for (size_t i = 0, L = b->length(); i < L; ++i) {
@@ -2080,17 +2086,19 @@ namespace Sass {
2080
2086
  if (b->is_root()) {
2081
2087
  // debug_subset_map(subset_map);
2082
2088
  for(auto const &it : subset_map.values()) {
2083
- Complex_Selector_Ptr sel = it.first ? &it.first->first() : NULL;
2084
- Compound_Selector_Ptr ext = it.second ? &it.second : NULL;
2089
+ Complex_Selector_Ptr sel = NULL;
2090
+ Compound_Selector_Ptr ext = NULL;
2091
+ if (it.first) sel = it.first->first();
2092
+ if (it.second) ext = it.second;
2085
2093
  if (ext && (ext->extended() || ext->is_optional())) continue;
2086
- std::string str_sel(sel->to_string({ NESTED, 5 }));
2087
- std::string str_ext(ext->to_string({ NESTED, 5 }));
2094
+ std::string str_sel(sel ? sel->to_string({ NESTED, 5 }) : "NULL");
2095
+ std::string str_ext(ext ? ext->to_string({ NESTED, 5 }) : "NULL");
2088
2096
  // debug_ast(sel, "sel: ");
2089
2097
  // debug_ast(ext, "ext: ");
2090
2098
  error("\"" + str_sel + "\" failed to @extend \"" + str_ext + "\".\n"
2091
2099
  "The selector \"" + str_ext + "\" was not found.\n"
2092
2100
  "Use \"@extend " + str_ext + " !optional\" if the"
2093
- " extend should be able to fail.", ext->pstate());
2101
+ " extend should be able to fail.", (ext ? ext->pstate() : NULL), eval->exp.traces);
2094
2102
  }
2095
2103
  }
2096
2104
 
@@ -2098,7 +2106,7 @@ namespace Sass {
2098
2106
 
2099
2107
  void Extend::operator()(Ruleset_Ptr pRuleset)
2100
2108
  {
2101
- extendObjectWithSelectorAndBlock( pRuleset, ctx, subset_map);
2109
+ extendObjectWithSelectorAndBlock( pRuleset );
2102
2110
  pRuleset->block()->perform(this);
2103
2111
  }
2104
2112
 
@@ -2114,7 +2122,7 @@ namespace Sass {
2114
2122
 
2115
2123
  void Extend::operator()(Directive_Ptr a)
2116
2124
  {
2117
- // Selector_List_Ptr ls = dynamic_cast<Selector_List_Ptr>(a->selector());
2125
+ // Selector_List_Ptr ls = Cast<Selector_List>(a->selector());
2118
2126
  // selector_stack.push_back(ls);
2119
2127
  if (a->block()) a->block()->perform(this);
2120
2128
  // exp.selector_stack.pop_back();