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.
- checksums.yaml +5 -5
- data/.travis.yml +2 -2
- data/CODE_OF_CONDUCT.md +10 -0
- data/README.md +4 -1
- data/ext/libsass/.editorconfig +1 -1
- data/ext/libsass/.github/CONTRIBUTING.md +7 -7
- data/ext/libsass/.github/ISSUE_TEMPLATE.md +31 -6
- data/ext/libsass/.gitignore +3 -0
- data/ext/libsass/.travis.yml +37 -18
- data/ext/libsass/GNUmakefile.am +23 -37
- data/ext/libsass/Makefile +10 -6
- data/ext/libsass/Makefile.conf +3 -0
- data/ext/libsass/Readme.md +68 -63
- data/ext/libsass/appveyor.yml +7 -3
- data/ext/libsass/configure.ac +10 -14
- data/ext/libsass/docs/api-context-internal.md +29 -21
- data/ext/libsass/docs/api-context.md +26 -6
- data/ext/libsass/docs/api-doc.md +49 -16
- data/ext/libsass/docs/api-function-example.md +1 -1
- data/ext/libsass/docs/api-function.md +31 -7
- data/ext/libsass/docs/api-importer.md +19 -19
- data/ext/libsass/docs/api-value.md +4 -2
- data/ext/libsass/docs/build-on-windows.md +4 -4
- data/ext/libsass/docs/build-with-mingw.md +3 -3
- data/ext/libsass/docs/build.md +9 -9
- data/ext/libsass/docs/custom-functions-internal.md +10 -8
- data/ext/libsass/docs/implementations.md +20 -8
- data/ext/libsass/docs/unicode.md +16 -10
- data/ext/libsass/include/sass/base.h +0 -3
- data/ext/libsass/include/sass/context.h +20 -2
- data/ext/libsass/include/sass/functions.h +31 -0
- data/ext/libsass/include/sass/values.h +3 -1
- data/ext/libsass/include/sass/version.h +1 -1
- data/ext/libsass/include/sass/version.h.in +1 -1
- data/ext/libsass/include/sass2scss.h +1 -1
- data/ext/libsass/res/resource.rc +6 -6
- data/ext/libsass/script/ci-build-libsass +10 -5
- data/ext/libsass/script/ci-build-plugin +62 -0
- data/ext/libsass/script/ci-install-compiler +1 -1
- data/ext/libsass/script/ci-install-deps +4 -7
- data/ext/libsass/script/ci-report-coverage +13 -3
- data/ext/libsass/script/tap-driver +1 -1
- data/ext/libsass/script/tap-runner +1 -1
- data/ext/libsass/src/GNUmakefile.am +1 -1
- data/ext/libsass/src/ast.cpp +537 -762
- data/ext/libsass/src/ast.hpp +377 -419
- data/ext/libsass/src/ast_def_macros.hpp +26 -1
- data/ext/libsass/src/ast_fwd_decl.cpp +29 -0
- data/ext/libsass/src/ast_fwd_decl.hpp +94 -21
- data/ext/libsass/src/b64/encode.h +3 -1
- data/ext/libsass/src/backtrace.cpp +46 -0
- data/ext/libsass/src/backtrace.hpp +7 -54
- data/ext/libsass/src/bind.cpp +72 -50
- data/ext/libsass/src/bind.hpp +0 -1
- data/ext/libsass/src/cencode.c +6 -0
- data/ext/libsass/src/check_nesting.cpp +157 -135
- data/ext/libsass/src/check_nesting.hpp +11 -10
- data/ext/libsass/src/color_maps.cpp +10 -6
- data/ext/libsass/src/color_maps.hpp +6 -8
- data/ext/libsass/src/constants.cpp +4 -3
- data/ext/libsass/src/constants.hpp +4 -3
- data/ext/libsass/src/context.cpp +110 -47
- data/ext/libsass/src/context.hpp +11 -1
- data/ext/libsass/src/cssize.cpp +105 -94
- data/ext/libsass/src/cssize.hpp +4 -5
- data/ext/libsass/src/debugger.hpp +247 -244
- data/ext/libsass/src/emitter.cpp +30 -6
- data/ext/libsass/src/emitter.hpp +7 -0
- data/ext/libsass/src/environment.cpp +67 -16
- data/ext/libsass/src/environment.hpp +28 -7
- data/ext/libsass/src/error_handling.cpp +92 -64
- data/ext/libsass/src/error_handling.hpp +64 -43
- data/ext/libsass/src/eval.cpp +494 -544
- data/ext/libsass/src/eval.hpp +17 -23
- data/ext/libsass/src/expand.cpp +182 -154
- data/ext/libsass/src/expand.hpp +4 -5
- data/ext/libsass/src/extend.cpp +299 -291
- data/ext/libsass/src/extend.hpp +46 -11
- data/ext/libsass/src/file.cpp +103 -36
- data/ext/libsass/src/file.hpp +21 -4
- data/ext/libsass/src/functions.cpp +561 -312
- data/ext/libsass/src/functions.hpp +8 -5
- data/ext/libsass/src/inspect.cpp +108 -53
- data/ext/libsass/src/inspect.hpp +5 -2
- data/ext/libsass/src/lexer.cpp +15 -7
- data/ext/libsass/src/lexer.hpp +13 -4
- data/ext/libsass/src/listize.cpp +3 -2
- data/ext/libsass/src/listize.hpp +0 -1
- data/ext/libsass/src/memory/SharedPtr.cpp +16 -18
- data/ext/libsass/src/memory/SharedPtr.hpp +47 -43
- data/ext/libsass/src/node.cpp +34 -38
- data/ext/libsass/src/node.hpp +6 -8
- data/ext/libsass/src/operation.hpp +2 -2
- data/ext/libsass/src/operators.cpp +240 -0
- data/ext/libsass/src/operators.hpp +30 -0
- data/ext/libsass/src/output.cpp +22 -20
- data/ext/libsass/src/parser.cpp +719 -358
- data/ext/libsass/src/parser.hpp +57 -22
- data/ext/libsass/src/plugins.cpp +28 -10
- data/ext/libsass/src/position.cpp +21 -3
- data/ext/libsass/src/position.hpp +2 -1
- data/ext/libsass/src/prelexer.cpp +104 -19
- data/ext/libsass/src/prelexer.hpp +10 -3
- data/ext/libsass/src/remove_placeholders.cpp +9 -10
- data/ext/libsass/src/remove_placeholders.hpp +1 -5
- data/ext/libsass/src/sass.cpp +62 -4
- data/ext/libsass/src/sass.hpp +5 -2
- data/ext/libsass/src/sass_context.cpp +96 -58
- data/ext/libsass/src/sass_context.hpp +7 -5
- data/ext/libsass/src/sass_functions.cpp +63 -1
- data/ext/libsass/src/sass_functions.hpp +19 -1
- data/ext/libsass/src/sass_util.cpp +3 -3
- data/ext/libsass/src/sass_util.hpp +4 -4
- data/ext/libsass/src/sass_values.cpp +42 -39
- data/ext/libsass/src/sass_values.hpp +2 -1
- data/ext/libsass/src/source_map.cpp +16 -18
- data/ext/libsass/src/subset_map.cpp +6 -8
- data/ext/libsass/src/subset_map.hpp +6 -6
- data/ext/libsass/src/to_c.cpp +2 -2
- data/ext/libsass/src/to_value.cpp +8 -3
- data/ext/libsass/src/to_value.hpp +1 -0
- data/ext/libsass/src/units.cpp +349 -45
- data/ext/libsass/src/units.hpp +39 -22
- data/ext/libsass/src/utf8/checked.h +7 -0
- data/ext/libsass/src/utf8/unchecked.h +7 -0
- data/ext/libsass/src/utf8_string.cpp +1 -1
- data/ext/libsass/src/util.cpp +139 -45
- data/ext/libsass/src/util.hpp +4 -7
- data/ext/libsass/src/values.cpp +15 -23
- data/ext/libsass/win/libsass.sln +13 -2
- data/ext/libsass/win/libsass.sln.DotSettings +9 -0
- data/ext/libsass/win/libsass.targets +3 -0
- data/ext/libsass/win/libsass.vcxproj.filters +9 -0
- data/lib/sassc/version.rb +1 -1
- data/sassc.gemspec +1 -1
- data/test/native_test.rb +1 -1
- metadata +11 -4
data/ext/libsass/src/expand.hpp
CHANGED
@@ -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
|
-
|
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*,
|
47
|
+
Expand(Context&, Env*, std::vector<Selector_List_Obj>* stack = NULL);
|
49
48
|
~Expand() { }
|
50
49
|
|
51
50
|
Block_Ptr operator()(Block_Ptr);
|
data/ext/libsass/src/extend.cpp
CHANGED
@@ -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(
|
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(
|
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
|
216
|
-
static void printSourcesSet(
|
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 (
|
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
|
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 << "
|
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,
|
246
|
+
std::ostream& operator<<(std::ostream& os, SubSetMapPairs& entries) {
|
253
247
|
os << "SUBSET_MAP_ENTRIES[";
|
254
248
|
|
255
|
-
for (
|
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
|
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(
|
296
|
-
Complex_Selector_Obj fakeParentContainer = SASS_MEMORY_NEW(Complex_Selector, ParserState("[FAKE]"), Complex_Selector::ANCESTOR_OF,
|
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(
|
299
|
-
pTwo->set_innermost(
|
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
|
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
|
305
|
+
out.push_back(nodeToComplexSelector(child));
|
313
306
|
}
|
314
307
|
}
|
315
308
|
|
316
|
-
Node complexSelectorDequeToNode(const ComplexSelectorDeque& deque
|
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(
|
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(
|
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 (
|
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(
|
344
|
+
if (parentSuperselector(pOne, pTwo)) {
|
354
345
|
pOut = pTwo;
|
355
346
|
return true;
|
356
347
|
}
|
357
348
|
|
358
|
-
if (parentSuperselector(
|
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(
|
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,
|
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
|
-
|
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
|
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
|
-
|
563
|
+
ComplexSelectorSet sources = pSeq1->sources();
|
573
564
|
|
574
565
|
DEBUG_PRINTLN(TRIM, "TRIM SEQ1: " << seq1)
|
575
|
-
DEBUG_EXEC(TRIM, printSourcesSet(sources,
|
566
|
+
DEBUG_EXEC(TRIM, printSourcesSet(sources, "TRIM SOURCES: "))
|
576
567
|
|
577
|
-
for (
|
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
|
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
|
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(
|
659
|
-
Complex_Selector_Obj fakeParentContainer = SASS_MEMORY_NEW(Complex_Selector, ParserState("[FAKE]"), Complex_Selector::ANCESTOR_OF,
|
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
|
662
|
-
pOneWithFakeParent->set_innermost(
|
663
|
-
Complex_Selector_Obj pTwoWithFakeParent = nodeToComplexSelector(two
|
664
|
-
pTwoWithFakeParent->set_innermost(
|
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
|
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()
|
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
|
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
|
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
|
838
|
+
Node opsLcs = lcs(ops1, ops2, lcsDefaultComparator);
|
850
839
|
|
851
|
-
if (!(
|
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,
|
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
|
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 (!(
|
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(
|
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(
|
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(
|
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(
|
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(
|
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(
|
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,
|
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,
|
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,
|
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
|
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
|
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,
|
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
|
1233
|
+
Node groupSeq1 = groupSelectors(seq1);
|
1249
1234
|
DEBUG_PRINTLN(SUBWEAVE, "SEQ1: " << groupSeq1)
|
1250
1235
|
|
1251
|
-
Node groupSeq2 = groupSelectors(seq2
|
1236
|
+
Node groupSeq2 = groupSelectors(seq2);
|
1252
1237
|
DEBUG_PRINTLN(SUBWEAVE, "SEQ2: " << groupSeq2)
|
1253
1238
|
|
1254
1239
|
|
1255
1240
|
ComplexSelectorDeque groupSeq1Converted;
|
1256
|
-
nodeToComplexSelectorDeque(groupSeq1, groupSeq1Converted
|
1241
|
+
nodeToComplexSelectorDeque(groupSeq1, groupSeq1Converted);
|
1257
1242
|
|
1258
1243
|
ComplexSelectorDeque groupSeq2Converted;
|
1259
|
-
nodeToComplexSelectorDeque(groupSeq2, groupSeq2Converted
|
1244
|
+
nodeToComplexSelectorDeque(groupSeq2, groupSeq2Converted);
|
1260
1245
|
|
1261
1246
|
ComplexSelectorDeque out;
|
1262
|
-
LcsCollectionComparator collectionComparator
|
1263
|
-
lcs(groupSeq2Converted, groupSeq1Converted, collectionComparator,
|
1264
|
-
Node seqLcs = complexSelectorDequeToNode(out
|
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
|
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
|
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
|
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
|
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(
|
1341
|
+
out.collection()->push_back(two.klone());
|
1357
1342
|
} else if (two.isNil()) {
|
1358
|
-
out.collection()->push_back(one.klone(
|
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(
|
1364
|
-
Node twoCloned = two.klone(
|
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(
|
1369
|
-
Node oneCloned = one.klone(
|
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
|
-
|
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(
|
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 =
|
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()(
|
1515
|
+
KeyType operator()(SubSetMapPair& extPair) const {
|
1534
1516
|
Complex_Selector_Obj pSelector = extPair.first;
|
1535
|
-
return
|
1517
|
+
return pSelector;
|
1536
1518
|
}
|
1537
1519
|
};
|
1538
|
-
|
1539
|
-
|
1540
|
-
|
1541
|
-
|
1542
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
1542
|
+
SubSetMapResults arr;
|
1556
1543
|
group_by_to_a(entries, extPairKeyFunctor, arr);
|
1557
1544
|
|
1558
|
-
|
1559
|
-
typedef std::vector<SelsNewSeqPair> SelsNewSeqPairCollection;
|
1560
|
-
|
1545
|
+
SubSetMapLookups holder;
|
1561
1546
|
|
1562
|
-
|
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
|
-
|
1551
|
+
SubSetMapPairs& group = groupedPair.second;
|
1570
1552
|
|
1571
|
-
DEBUG_EXEC(EXTEND_COMPOUND, printComplexSelector(
|
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 (
|
1576
|
-
|
1577
|
-
|
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(
|
1561
|
+
DEBUG_EXEC(EXTEND_COMPOUND, printCompoundSelector(pSels, "SELS: "))
|
1586
1562
|
|
1587
|
-
|
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(
|
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(
|
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(
|
1601
|
+
pNewSelector->set_innermost(pNewInnerMost, combinator);
|
1625
1602
|
|
1626
1603
|
#ifdef DEBUG
|
1627
|
-
|
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
|
1618
|
+
DEBUG_PRINTLN(EXTEND_COMPOUND, "SOURCES SETTING ON NEW SEQ: " << complexSelectorToNode(pNewSelector))
|
1642
1619
|
|
1643
|
-
DEBUG_EXEC(EXTEND_COMPOUND,
|
1620
|
+
DEBUG_EXEC(EXTEND_COMPOUND, ComplexSelectorSet oldSet = pNewSelector->sources(); printSourcesSet(oldSet, "SOURCES NEW SEQ BEGIN: "))
|
1644
1621
|
|
1645
|
-
|
1646
|
-
|
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,
|
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
|
1630
|
+
pNewSelector->addSources(newSourcesSet);
|
1653
1631
|
|
1654
|
-
DEBUG_EXEC(EXTEND_COMPOUND,
|
1655
|
-
DEBUG_EXEC(EXTEND_COMPOUND, printSourcesSet(pSelector->sources(),
|
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 (
|
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(
|
1649
|
+
if (seen.find(pSels) != seen.end()) {
|
1673
1650
|
continue;
|
1674
1651
|
}
|
1675
1652
|
|
1676
1653
|
|
1677
|
-
|
1678
|
-
recurseSeen.insert(
|
1654
|
+
CompoundSelectorSet recurseSeen(seen);
|
1655
|
+
recurseSeen.insert(pSels);
|
1679
1656
|
|
1680
1657
|
|
1681
|
-
DEBUG_PRINTLN(EXTEND_COMPOUND, "RECURSING DO EXTEND: " << complexSelectorToNode(pNewSelector
|
1682
|
-
Node recurseExtendedSelectors = extendComplexSelector(
|
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: " <<
|
1691
|
-
// DEBUG_PRINTLN(EXTEND_COMPOUND, "SELECTOR EXISTS ALREADY: " << newSelector << " " <<
|
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 (!
|
1670
|
+
if (!results.contains(newSelector)) {
|
1694
1671
|
// DEBUG_PRINTLN(EXTEND_COMPOUND, "ADDING NEW SELECTOR")
|
1695
|
-
|
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
|
-
|
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
|
-
|
1707
|
-
|
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 =
|
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
|
-
|
1721
|
-
for (
|
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(
|
1730
|
-
std::string query_right(pHead->media_block()->media_queries()->to_string(
|
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(
|
1719
|
+
err << "From \"@extend " << ext.second->to_string() << "\"";
|
1742
1720
|
err << " on line " << pstate.line+1 << " of " << rel_path << "\n";
|
1743
|
-
error(err.str(),
|
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
|
-
|
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
|
-
|
1773
|
-
|
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
|
-
|
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
|
-
|
1778
|
-
|
1779
|
-
|
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
|
-
|
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
|
-
|
1775
|
+
choices.collection()->push_back(outer);
|
1796
1776
|
continue;
|
1797
1777
|
}
|
1798
1778
|
|
1799
|
-
|
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(
|
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
|
-
//
|
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 && !
|
1813
|
-
|
1814
|
-
srcset.insert(
|
1815
|
-
|
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
|
-
|
1821
|
-
|
1822
|
-
|
1823
|
-
|
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
|
-
|
1832
|
-
|
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
|
-
|
1820
|
+
choices.collection()->push_back(extended);
|
1839
1821
|
}
|
1840
1822
|
|
1841
1823
|
|
1842
|
-
DEBUG_PRINTLN(EXTEND_COMPLEX, "EXTENDED NOT EXPANDED: " <<
|
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(
|
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
|
1857
|
-
|
1858
|
-
|
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
|
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
|
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
|
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
|
-
|
1891
|
-
|
1892
|
-
|
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
|
-
|
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(
|
1913
|
-
pNewSelectors->append(
|
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
|
-
|
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
|
-
|
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
|
-
|
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(
|
1930
|
-
|
1931
|
-
|
1932
|
-
|
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
|
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(
|
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(
|
1947
|
-
|
1948
|
-
recseen.insert(
|
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 =
|
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 =
|
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
|
-
|
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(
|
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
|
-
|
1971
|
-
|
1972
|
-
|
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(
|
1965
|
+
cpy_ws->selector(cpy_ws_sl);
|
1985
1966
|
// append the clone
|
1986
|
-
cpy_head->append(
|
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(
|
1984
|
+
cpy_head->append(hs);
|
1992
1985
|
}
|
1993
1986
|
} else {
|
1994
|
-
cpy_head->append(
|
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 (
|
2028
|
-
// Do nothing. This doesn't count as a statement that causes extension since we'll
|
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
|
-
|
2042
|
-
|
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: " <<
|
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.
|
2047
|
-
// of doing so, so for now, let's just not extend things
|
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
|
-
|
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: " <<
|
2058
|
-
DEBUG_PRINTLN(EXTEND_OBJECT, "EXTEND SETTING NEW SELECTORS: " << pNewSelectorList->to_string(
|
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(
|
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 =
|
2084
|
-
Compound_Selector_Ptr ext =
|
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
|
-
|
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
|
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 =
|
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();
|