sassc 1.11.4 → 1.12.0

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