sassc 1.10.1 → 1.11.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +5 -2
- data/ext/libsass/.github/CONTRIBUTING.md +65 -0
- data/ext/libsass/.github/ISSUE_TEMPLATE.md +29 -0
- data/ext/libsass/Makefile +8 -3
- data/ext/libsass/Makefile.conf +28 -22
- data/ext/libsass/Readme.md +14 -7
- data/ext/libsass/configure.ac +5 -8
- data/ext/libsass/docs/api-context-internal.md +3 -0
- data/ext/libsass/docs/api-context.md +7 -0
- data/ext/libsass/docs/api-doc.md +4 -0
- data/ext/libsass/docs/api-importer.md +2 -0
- data/ext/libsass/docs/api-value-example.md +55 -0
- data/ext/libsass/docs/api-value.md +49 -22
- data/ext/libsass/docs/implementations.md +4 -0
- data/ext/libsass/include/sass/base.h +5 -4
- data/ext/libsass/include/sass/context.h +3 -0
- data/ext/libsass/include/sass/values.h +28 -27
- data/ext/libsass/include/sass/version.h +1 -1
- data/ext/libsass/include/sass2scss.h +1 -1
- data/ext/libsass/script/ci-build-libsass +3 -3
- data/ext/libsass/script/ci-install-deps +12 -3
- data/ext/libsass/src/ast.cpp +321 -212
- data/ext/libsass/src/ast.hpp +273 -165
- data/ext/libsass/src/ast_factory.hpp +4 -5
- data/ext/libsass/src/ast_fwd_decl.hpp +8 -7
- data/ext/libsass/src/bind.cpp +2 -7
- data/ext/libsass/src/bind.hpp +0 -1
- data/ext/libsass/src/check_nesting.cpp +379 -0
- data/ext/libsass/src/check_nesting.hpp +60 -0
- data/ext/libsass/src/constants.cpp +7 -6
- data/ext/libsass/src/constants.hpp +2 -1
- data/ext/libsass/src/context.cpp +7 -1
- data/ext/libsass/src/context.hpp +1 -1
- data/ext/libsass/src/cssize.cpp +76 -32
- data/ext/libsass/src/cssize.hpp +7 -8
- data/ext/libsass/src/debugger.hpp +70 -40
- data/ext/libsass/src/error_handling.cpp +15 -2
- data/ext/libsass/src/error_handling.hpp +19 -0
- data/ext/libsass/src/eval.cpp +107 -161
- data/ext/libsass/src/eval.hpp +12 -8
- data/ext/libsass/src/expand.cpp +81 -74
- data/ext/libsass/src/expand.hpp +13 -12
- data/ext/libsass/src/extend.cpp +149 -142
- data/ext/libsass/src/extend.hpp +10 -3
- data/ext/libsass/src/file.cpp +2 -1
- data/ext/libsass/src/functions.cpp +96 -59
- data/ext/libsass/src/functions.hpp +2 -2
- data/ext/libsass/src/inspect.cpp +33 -45
- data/ext/libsass/src/inspect.hpp +7 -7
- data/ext/libsass/src/json.cpp +17 -5
- data/ext/libsass/src/lexer.cpp +3 -3
- data/ext/libsass/src/listize.cpp +10 -10
- data/ext/libsass/src/listize.hpp +3 -3
- data/ext/libsass/src/node.cpp +30 -30
- data/ext/libsass/src/node.hpp +13 -13
- data/ext/libsass/src/operation.hpp +21 -19
- data/ext/libsass/src/output.cpp +48 -103
- data/ext/libsass/src/output.hpp +0 -1
- data/ext/libsass/src/parser.cpp +161 -133
- data/ext/libsass/src/parser.hpp +10 -7
- data/ext/libsass/src/remove_placeholders.cpp +6 -6
- data/ext/libsass/src/remove_placeholders.hpp +1 -1
- data/ext/libsass/src/sass.cpp +21 -0
- data/ext/libsass/src/sass.hpp +8 -1
- data/ext/libsass/src/sass2scss.cpp +14 -3
- data/ext/libsass/src/sass_context.cpp +69 -24
- data/ext/libsass/src/sass_context.hpp +3 -0
- data/ext/libsass/src/source_map.cpp +22 -10
- data/ext/libsass/src/to_value.cpp +2 -2
- data/ext/libsass/src/to_value.hpp +1 -1
- data/ext/libsass/src/units.hpp +3 -1
- data/ext/libsass/src/util.cpp +20 -16
- data/ext/libsass/src/util.hpp +2 -1
- data/ext/libsass/win/libsass.targets +2 -0
- data/ext/libsass/win/libsass.vcxproj.filters +6 -0
- data/lib/sassc/engine.rb +5 -0
- data/lib/sassc/native/native_functions_api.rb +13 -1
- data/lib/sassc/script/value_conversion.rb +11 -1
- data/lib/sassc/script/value_conversion/list.rb +23 -0
- data/lib/sassc/version.rb +1 -1
- data/test/engine_test.rb +18 -2
- data/test/functions_test.rb +30 -0
- data/test/native_test.rb +1 -1
- metadata +8 -3
data/ext/libsass/src/eval.hpp
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
|
4
4
|
#include "ast.hpp"
|
5
5
|
#include "context.hpp"
|
6
|
+
#include "listize.hpp"
|
6
7
|
#include "operation.hpp"
|
7
8
|
#include "environment.hpp"
|
8
9
|
|
@@ -22,11 +23,12 @@ namespace Sass {
|
|
22
23
|
Eval(Expand& exp);
|
23
24
|
~Eval();
|
24
25
|
|
26
|
+
bool force;
|
25
27
|
bool is_in_comment;
|
26
28
|
|
27
29
|
Env* environment();
|
28
30
|
Context& context();
|
29
|
-
|
31
|
+
CommaSequence_Selector* selector();
|
30
32
|
Backtrace* backtrace();
|
31
33
|
|
32
34
|
// for evaluating function bodies
|
@@ -50,11 +52,12 @@ namespace Sass {
|
|
50
52
|
Expression* operator()(Variable*);
|
51
53
|
Expression* operator()(Textual*);
|
52
54
|
Expression* operator()(Number*);
|
55
|
+
Expression* operator()(Color*);
|
53
56
|
Expression* operator()(Boolean*);
|
54
57
|
Expression* operator()(String_Schema*);
|
55
58
|
Expression* operator()(String_Quoted*);
|
56
59
|
Expression* operator()(String_Constant*);
|
57
|
-
// Expression* operator()(
|
60
|
+
// Expression* operator()(CommaSequence_Selector*);
|
58
61
|
Expression* operator()(Media_Query*);
|
59
62
|
Expression* operator()(Media_Query_Expression*);
|
60
63
|
Expression* operator()(At_Root_Query*);
|
@@ -68,17 +71,18 @@ namespace Sass {
|
|
68
71
|
Expression* operator()(Comment*);
|
69
72
|
|
70
73
|
// these will return selectors
|
71
|
-
|
72
|
-
|
74
|
+
CommaSequence_Selector* operator()(CommaSequence_Selector*);
|
75
|
+
CommaSequence_Selector* operator()(Sequence_Selector*);
|
73
76
|
Attribute_Selector* operator()(Attribute_Selector*);
|
74
77
|
// they don't have any specific implementatio (yet)
|
75
|
-
|
78
|
+
Element_Selector* operator()(Element_Selector* s) { return s; };
|
76
79
|
Pseudo_Selector* operator()(Pseudo_Selector* s) { return s; };
|
77
80
|
Wrapped_Selector* operator()(Wrapped_Selector* s) { return s; };
|
78
|
-
|
79
|
-
|
81
|
+
Class_Selector* operator()(Class_Selector* s) { return s; };
|
82
|
+
Id_Selector* operator()(Id_Selector* s) { return s; };
|
83
|
+
Placeholder_Selector* operator()(Placeholder_Selector* s) { return s; };
|
80
84
|
// actual evaluated selectors
|
81
|
-
|
85
|
+
CommaSequence_Selector* operator()(Selector_Schema*);
|
82
86
|
Expression* operator()(Parent_Selector*);
|
83
87
|
|
84
88
|
template <typename U>
|
data/ext/libsass/src/expand.cpp
CHANGED
@@ -11,17 +11,23 @@
|
|
11
11
|
|
12
12
|
namespace Sass {
|
13
13
|
|
14
|
-
|
14
|
+
// simple endless recursion protection
|
15
|
+
const unsigned int maxRecursion = 500;
|
16
|
+
static unsigned int recursions = 0;
|
17
|
+
|
18
|
+
Expand::Expand(Context& ctx, Env* env, Backtrace* bt, std::vector<CommaSequence_Selector*>* stack)
|
15
19
|
: ctx(ctx),
|
16
20
|
eval(Eval(*this)),
|
17
21
|
env_stack(std::vector<Env*>()),
|
18
22
|
block_stack(std::vector<Block*>()),
|
19
23
|
call_stack(std::vector<AST_Node*>()),
|
20
24
|
property_stack(std::vector<String*>()),
|
21
|
-
selector_stack(std::vector<
|
25
|
+
selector_stack(std::vector<CommaSequence_Selector*>()),
|
22
26
|
media_block_stack(std::vector<Media_Block*>()),
|
23
27
|
backtrace_stack(std::vector<Backtrace*>()),
|
24
|
-
in_keyframes(false)
|
28
|
+
in_keyframes(false),
|
29
|
+
at_root_without_rule(false),
|
30
|
+
old_at_root_without_rule(false)
|
25
31
|
{
|
26
32
|
env_stack.push_back(0);
|
27
33
|
env_stack.push_back(env);
|
@@ -29,7 +35,8 @@ namespace Sass {
|
|
29
35
|
call_stack.push_back(0);
|
30
36
|
// import_stack.push_back(0);
|
31
37
|
property_stack.push_back(0);
|
32
|
-
selector_stack.push_back(0);
|
38
|
+
if (stack == NULL) { selector_stack.push_back(0); }
|
39
|
+
else { selector_stack.insert(selector_stack.end(), stack->begin(), stack->end()); }
|
33
40
|
media_block_stack.push_back(0);
|
34
41
|
backtrace_stack.push_back(0);
|
35
42
|
backtrace_stack.push_back(bt);
|
@@ -47,7 +54,7 @@ namespace Sass {
|
|
47
54
|
return 0;
|
48
55
|
}
|
49
56
|
|
50
|
-
|
57
|
+
CommaSequence_Selector* Expand::selector()
|
51
58
|
{
|
52
59
|
if (selector_stack.size() > 0)
|
53
60
|
return selector_stack.back();
|
@@ -86,23 +93,26 @@ namespace Sass {
|
|
86
93
|
|
87
94
|
Statement* Expand::operator()(Ruleset* r)
|
88
95
|
{
|
89
|
-
|
96
|
+
LOCAL_FLAG(old_at_root_without_rule, at_root_without_rule);
|
90
97
|
|
91
98
|
if (in_keyframes) {
|
92
99
|
Keyframe_Rule* k = SASS_MEMORY_NEW(ctx.mem, Keyframe_Rule, r->pstate(), r->block()->perform(this)->block());
|
93
100
|
if (r->selector()) {
|
94
101
|
selector_stack.push_back(0);
|
95
|
-
k->selector(static_cast<
|
102
|
+
k->selector(static_cast<CommaSequence_Selector*>(r->selector()->perform(&eval)));
|
96
103
|
selector_stack.pop_back();
|
97
104
|
}
|
98
105
|
return k;
|
99
106
|
}
|
100
107
|
|
108
|
+
// reset when leaving scope
|
109
|
+
LOCAL_FLAG(at_root_without_rule, false);
|
110
|
+
|
101
111
|
// do some special checks for the base level rules
|
102
112
|
if (r->is_root()) {
|
103
|
-
if (
|
104
|
-
for (
|
105
|
-
|
113
|
+
if (CommaSequence_Selector* selector_list = dynamic_cast<CommaSequence_Selector*>(r->selector())) {
|
114
|
+
for (Sequence_Selector* complex_selector : selector_list->elements()) {
|
115
|
+
Sequence_Selector* tail = complex_selector;
|
106
116
|
while (tail) {
|
107
117
|
if (tail->head()) for (Simple_Selector* header : tail->head()->elements()) {
|
108
118
|
if (dynamic_cast<Parent_Selector*>(header) == NULL) continue; // skip all others
|
@@ -116,13 +126,13 @@ namespace Sass {
|
|
116
126
|
}
|
117
127
|
|
118
128
|
Expression* ex = r->selector()->perform(&eval);
|
119
|
-
|
129
|
+
CommaSequence_Selector* sel = dynamic_cast<CommaSequence_Selector*>(ex);
|
120
130
|
if (sel == 0) throw std::runtime_error("Expanded null selector");
|
121
131
|
|
122
132
|
if (sel->length() == 0 || sel->has_parent_ref()) {
|
123
133
|
bool has_parent_selector = false;
|
124
134
|
for (size_t i = 0, L = selector_stack.size(); i < L && !has_parent_selector; i++) {
|
125
|
-
|
135
|
+
CommaSequence_Selector* ll = selector_stack.at(i);
|
126
136
|
has_parent_selector = ll != 0 && ll->length() > 0;
|
127
137
|
}
|
128
138
|
if (!has_parent_selector) {
|
@@ -131,10 +141,9 @@ namespace Sass {
|
|
131
141
|
}
|
132
142
|
|
133
143
|
selector_stack.push_back(sel);
|
134
|
-
Env
|
144
|
+
Env env(environment());
|
135
145
|
if (block_stack.back()->is_root()) {
|
136
|
-
env
|
137
|
-
env_stack.push_back(env);
|
146
|
+
env_stack.push_back(&env);
|
138
147
|
}
|
139
148
|
sel->set_media_block(media_block_stack.back());
|
140
149
|
Block* blk = r->block()->perform(this)->block();
|
@@ -145,48 +154,14 @@ namespace Sass {
|
|
145
154
|
selector_stack.pop_back();
|
146
155
|
if (block_stack.back()->is_root()) {
|
147
156
|
env_stack.pop_back();
|
148
|
-
delete env;
|
149
157
|
}
|
158
|
+
|
150
159
|
rr->is_root(r->is_root());
|
151
160
|
rr->tabs(r->tabs());
|
152
161
|
|
153
162
|
return rr;
|
154
163
|
}
|
155
164
|
|
156
|
-
Statement* Expand::operator()(Propset* p)
|
157
|
-
{
|
158
|
-
property_stack.push_back(p->property_fragment());
|
159
|
-
Block* expanded_block = p->block()->perform(this)->block();
|
160
|
-
|
161
|
-
for (size_t i = 0, L = expanded_block->length(); i < L; ++i) {
|
162
|
-
Statement* stm = (*expanded_block)[i];
|
163
|
-
if (Declaration* dec = static_cast<Declaration*>(stm)) {
|
164
|
-
String_Schema* combined_prop = SASS_MEMORY_NEW(ctx.mem, String_Schema, p->pstate());
|
165
|
-
if (!property_stack.empty()) {
|
166
|
-
*combined_prop << property_stack.back()->perform(&eval)
|
167
|
-
<< SASS_MEMORY_NEW(ctx.mem, String_Quoted,
|
168
|
-
p->pstate(), "-")
|
169
|
-
<< dec->property(); // TODO: eval the prop into a string constant
|
170
|
-
}
|
171
|
-
else {
|
172
|
-
*combined_prop << dec->property();
|
173
|
-
}
|
174
|
-
dec->property(combined_prop);
|
175
|
-
*block_stack.back() << dec;
|
176
|
-
}
|
177
|
-
else if (typeid(*stm) == typeid(Comment)) {
|
178
|
-
// drop comments in propsets
|
179
|
-
}
|
180
|
-
else {
|
181
|
-
error("contents of namespaced properties must result in style declarations only", stm->pstate(), backtrace());
|
182
|
-
}
|
183
|
-
}
|
184
|
-
|
185
|
-
property_stack.pop_back();
|
186
|
-
|
187
|
-
return 0;
|
188
|
-
}
|
189
|
-
|
190
165
|
Statement* Expand::operator()(Supports_Block* f)
|
191
166
|
{
|
192
167
|
Expression* condition = f->condition()->perform(&eval);
|
@@ -219,16 +194,19 @@ namespace Sass {
|
|
219
194
|
Statement* Expand::operator()(At_Root_Block* a)
|
220
195
|
{
|
221
196
|
Block* ab = a->block();
|
222
|
-
// if (ab) ab->is_root(true);
|
223
197
|
Expression* ae = a->expression();
|
198
|
+
|
224
199
|
if (ae) ae = ae->perform(&eval);
|
225
200
|
else ae = SASS_MEMORY_NEW(ctx.mem, At_Root_Query, a->pstate());
|
201
|
+
|
202
|
+
LOCAL_FLAG(at_root_without_rule, true);
|
203
|
+
LOCAL_FLAG(in_keyframes, false);
|
204
|
+
|
226
205
|
Block* bb = ab ? ab->perform(this)->block() : 0;
|
227
206
|
At_Root_Block* aa = SASS_MEMORY_NEW(ctx.mem, At_Root_Block,
|
228
207
|
a->pstate(),
|
229
208
|
bb,
|
230
209
|
static_cast<At_Root_Query*>(ae));
|
231
|
-
// aa->block()->is_root(true);
|
232
210
|
return aa;
|
233
211
|
}
|
234
212
|
|
@@ -254,15 +232,20 @@ namespace Sass {
|
|
254
232
|
|
255
233
|
Statement* Expand::operator()(Declaration* d)
|
256
234
|
{
|
235
|
+
Block* ab = d->block();
|
257
236
|
String* old_p = d->property();
|
258
237
|
String* new_p = static_cast<String*>(old_p->perform(&eval));
|
259
238
|
Expression* value = d->value()->perform(&eval);
|
260
|
-
|
239
|
+
Block* bb = ab ? ab->perform(this)->block() : 0;
|
240
|
+
if (!bb) {
|
241
|
+
if (!value || (value->is_invisible() && !d->is_important())) return 0;
|
242
|
+
}
|
261
243
|
Declaration* decl = SASS_MEMORY_NEW(ctx.mem, Declaration,
|
262
244
|
d->pstate(),
|
263
245
|
new_p,
|
264
246
|
value,
|
265
|
-
d->is_important()
|
247
|
+
d->is_important(),
|
248
|
+
bb);
|
266
249
|
decl->tabs(d->tabs());
|
267
250
|
return decl;
|
268
251
|
}
|
@@ -477,7 +460,7 @@ namespace Sass {
|
|
477
460
|
if (expr->concrete_type() == Expression::MAP) {
|
478
461
|
map = static_cast<Map*>(expr);
|
479
462
|
}
|
480
|
-
else if (
|
463
|
+
else if (CommaSequence_Selector* ls = dynamic_cast<CommaSequence_Selector*>(expr)) {
|
481
464
|
Listize listize(ctx.mem);
|
482
465
|
list = dynamic_cast<List*>(ls->perform(&listize));
|
483
466
|
}
|
@@ -513,7 +496,7 @@ namespace Sass {
|
|
513
496
|
}
|
514
497
|
else {
|
515
498
|
// bool arglist = list->is_arglist();
|
516
|
-
if (list->length() == 1 && dynamic_cast<
|
499
|
+
if (list->length() == 1 && dynamic_cast<CommaSequence_Selector*>(list)) {
|
517
500
|
list = dynamic_cast<Vectorized<Expression*>*>(list);
|
518
501
|
}
|
519
502
|
for (size_t i = 0, L = list->length(); i < L; ++i) {
|
@@ -573,11 +556,11 @@ namespace Sass {
|
|
573
556
|
}
|
574
557
|
|
575
558
|
|
576
|
-
void Expand::expand_selector_list(Selector* s,
|
559
|
+
void Expand::expand_selector_list(Selector* s, CommaSequence_Selector* extender) {
|
577
560
|
|
578
|
-
if (
|
579
|
-
for (
|
580
|
-
|
561
|
+
if (CommaSequence_Selector* sl = dynamic_cast<CommaSequence_Selector*>(s)) {
|
562
|
+
for (Sequence_Selector* complex_selector : sl->elements()) {
|
563
|
+
Sequence_Selector* tail = complex_selector;
|
581
564
|
while (tail) {
|
582
565
|
if (tail->head()) for (Simple_Selector* header : tail->head()->elements()) {
|
583
566
|
if (dynamic_cast<Parent_Selector*>(header) == NULL) continue; // skip all others
|
@@ -590,24 +573,24 @@ namespace Sass {
|
|
590
573
|
}
|
591
574
|
|
592
575
|
|
593
|
-
|
576
|
+
CommaSequence_Selector* contextualized = dynamic_cast<CommaSequence_Selector*>(s->perform(&eval));
|
594
577
|
if (contextualized == NULL) return;
|
595
578
|
for (auto complex_sel : contextualized->elements()) {
|
596
|
-
|
579
|
+
Sequence_Selector* c = complex_sel;
|
597
580
|
if (!c->head() || c->tail()) {
|
598
581
|
std::string sel_str(contextualized->to_string(ctx.c_options));
|
599
582
|
error("Can't extend " + sel_str + ": can't extend nested selectors", c->pstate(), backtrace());
|
600
583
|
}
|
601
|
-
|
584
|
+
SimpleSequence_Selector* placeholder = c->head();
|
602
585
|
if (contextualized->is_optional()) placeholder->is_optional(true);
|
603
586
|
for (size_t i = 0, L = extender->length(); i < L; ++i) {
|
604
|
-
|
587
|
+
Sequence_Selector* sel = (*extender)[i];
|
605
588
|
if (!(sel->head() && sel->head()->length() > 0 &&
|
606
589
|
dynamic_cast<Parent_Selector*>((*sel->head())[0])))
|
607
590
|
{
|
608
|
-
|
591
|
+
SimpleSequence_Selector* hh = SASS_MEMORY_NEW(ctx.mem, SimpleSequence_Selector, (*extender)[i]->pstate());
|
609
592
|
hh->media_block((*extender)[i]->media_block());
|
610
|
-
|
593
|
+
Sequence_Selector* ssel = SASS_MEMORY_NEW(ctx.mem, Sequence_Selector, (*extender)[i]->pstate());
|
611
594
|
ssel->media_block((*extender)[i]->media_block());
|
612
595
|
if (sel->has_line_feed()) ssel->has_line_feed(true);
|
613
596
|
Parent_Selector* ps = SASS_MEMORY_NEW(ctx.mem, Parent_Selector, (*extender)[i]->pstate());
|
@@ -626,13 +609,13 @@ namespace Sass {
|
|
626
609
|
|
627
610
|
Statement* Expand::operator()(Extension* e)
|
628
611
|
{
|
629
|
-
if (
|
612
|
+
if (CommaSequence_Selector* extender = dynamic_cast<CommaSequence_Selector*>(selector())) {
|
630
613
|
Selector* s = e->selector();
|
631
614
|
if (Selector_Schema* schema = dynamic_cast<Selector_Schema*>(s)) {
|
632
615
|
if (schema->has_parent_ref()) s = eval(schema);
|
633
616
|
}
|
634
|
-
if (
|
635
|
-
for (
|
617
|
+
if (CommaSequence_Selector* sl = dynamic_cast<CommaSequence_Selector*>(s)) {
|
618
|
+
for (Sequence_Selector* cs : *sl) {
|
636
619
|
if (cs != NULL && cs->head() != NULL) {
|
637
620
|
cs->head()->media_block(media_block_stack.back());
|
638
621
|
}
|
@@ -673,6 +656,12 @@ namespace Sass {
|
|
673
656
|
|
674
657
|
Statement* Expand::operator()(Mixin_Call* c)
|
675
658
|
{
|
659
|
+
recursions ++;
|
660
|
+
|
661
|
+
if (recursions > maxRecursion) {
|
662
|
+
throw Exception::StackError(*c);
|
663
|
+
}
|
664
|
+
|
676
665
|
Env* env = environment();
|
677
666
|
std::string full_name(c->name() + "[m]");
|
678
667
|
if (!env->has(full_name)) {
|
@@ -704,10 +693,23 @@ namespace Sass {
|
|
704
693
|
}
|
705
694
|
|
706
695
|
bind(std::string("Mixin"), c->name(), params, args, &ctx, &new_env, &eval);
|
707
|
-
|
708
|
-
|
696
|
+
|
697
|
+
Block* trace_block = SASS_MEMORY_NEW(ctx.mem, Block, c->pstate());
|
698
|
+
Trace* trace = SASS_MEMORY_NEW(ctx.mem, Trace, c->pstate(), c->name(), trace_block);
|
699
|
+
|
700
|
+
|
701
|
+
block_stack.push_back(trace_block);
|
702
|
+
for (auto bb : *body) {
|
703
|
+
Statement* ith = bb->perform(this);
|
704
|
+
if (ith) *trace->block() << ith;
|
705
|
+
}
|
706
|
+
block_stack.pop_back();
|
707
|
+
|
709
708
|
env_stack.pop_back();
|
710
|
-
|
709
|
+
backtrace_stack.pop_back();
|
710
|
+
|
711
|
+
recursions --;
|
712
|
+
return trace;
|
711
713
|
}
|
712
714
|
|
713
715
|
Statement* Expand::operator()(Content* c)
|
@@ -715,18 +717,23 @@ namespace Sass {
|
|
715
717
|
Env* env = environment();
|
716
718
|
// convert @content directives into mixin calls to the underlying thunk
|
717
719
|
if (!env->has("@content[m]")) return 0;
|
720
|
+
|
718
721
|
if (block_stack.back()->is_root()) {
|
719
722
|
selector_stack.push_back(0);
|
720
723
|
}
|
724
|
+
|
721
725
|
Mixin_Call* call = SASS_MEMORY_NEW(ctx.mem, Mixin_Call,
|
722
726
|
c->pstate(),
|
723
727
|
"@content",
|
724
728
|
SASS_MEMORY_NEW(ctx.mem, Arguments, c->pstate()));
|
725
|
-
|
729
|
+
|
730
|
+
Trace* trace = dynamic_cast<Trace*>(call->perform(this));
|
731
|
+
|
726
732
|
if (block_stack.back()->is_root()) {
|
727
733
|
selector_stack.pop_back();
|
728
734
|
}
|
729
|
-
|
735
|
+
|
736
|
+
return trace;
|
730
737
|
}
|
731
738
|
|
732
739
|
// produce an error if something is not implemented
|
data/ext/libsass/src/expand.hpp
CHANGED
@@ -21,34 +21,35 @@ namespace Sass {
|
|
21
21
|
|
22
22
|
Env* environment();
|
23
23
|
Context& context();
|
24
|
-
|
24
|
+
CommaSequence_Selector* selector();
|
25
25
|
Backtrace* backtrace();
|
26
26
|
|
27
27
|
Context& ctx;
|
28
28
|
Eval eval;
|
29
29
|
|
30
30
|
// it's easier to work with vectors
|
31
|
-
std::vector<Env*>
|
32
|
-
std::vector<Block*>
|
33
|
-
std::vector<AST_Node*>
|
34
|
-
std::vector<String*>
|
35
|
-
std::vector<
|
36
|
-
std::vector<Media_Block*>
|
37
|
-
std::vector<Backtrace*>backtrace_stack;
|
38
|
-
bool
|
31
|
+
std::vector<Env*> env_stack;
|
32
|
+
std::vector<Block*> block_stack;
|
33
|
+
std::vector<AST_Node*> call_stack;
|
34
|
+
std::vector<String*> property_stack;
|
35
|
+
std::vector<CommaSequence_Selector*> selector_stack;
|
36
|
+
std::vector<Media_Block*> media_block_stack;
|
37
|
+
std::vector<Backtrace*> backtrace_stack;
|
38
|
+
bool in_keyframes;
|
39
|
+
bool at_root_without_rule;
|
40
|
+
bool old_at_root_without_rule;
|
39
41
|
|
40
42
|
Statement* fallback_impl(AST_Node* n);
|
41
43
|
|
42
44
|
private:
|
43
|
-
void expand_selector_list(Selector*,
|
45
|
+
void expand_selector_list(Selector*, CommaSequence_Selector* extender);
|
44
46
|
|
45
47
|
public:
|
46
|
-
Expand(Context&, Env*, Backtrace
|
48
|
+
Expand(Context&, Env*, Backtrace*, std::vector<CommaSequence_Selector*>* stack = NULL);
|
47
49
|
~Expand() { }
|
48
50
|
|
49
51
|
Statement* operator()(Block*);
|
50
52
|
Statement* operator()(Ruleset*);
|
51
|
-
Statement* operator()(Propset*);
|
52
53
|
Statement* operator()(Media_Block*);
|
53
54
|
Statement* operator()(Supports_Block*);
|
54
55
|
Statement* operator()(At_Root_Block*);
|
data/ext/libsass/src/extend.cpp
CHANGED
@@ -62,26 +62,26 @@
|
|
62
62
|
namespace Sass {
|
63
63
|
|
64
64
|
|
65
|
-
typedef std::pair<
|
65
|
+
typedef std::pair<Sequence_Selector*, SimpleSequence_Selector*> ExtensionPair;
|
66
66
|
typedef std::vector<ExtensionPair> SubsetMapEntries;
|
67
67
|
|
68
68
|
#ifdef DEBUG
|
69
69
|
|
70
70
|
// TODO: move the ast specific ostream operators into ast.hpp/ast.cpp
|
71
|
-
std::ostream& operator<<(std::ostream& os, const
|
71
|
+
std::ostream& operator<<(std::ostream& os, const Sequence_Selector::Combinator combinator) {
|
72
72
|
switch (combinator) {
|
73
|
-
case
|
74
|
-
case
|
75
|
-
case
|
76
|
-
case
|
77
|
-
case
|
73
|
+
case Sequence_Selector::ANCESTOR_OF: os << "\" \""; break;
|
74
|
+
case Sequence_Selector::PARENT_OF: os << "\">\""; break;
|
75
|
+
case Sequence_Selector::PRECEDES: os << "\"~\""; break;
|
76
|
+
case Sequence_Selector::ADJACENT_TO: os << "\"+\""; break;
|
77
|
+
case Sequence_Selector::REFERENCE: os << "\"/\""; break;
|
78
78
|
}
|
79
79
|
|
80
80
|
return os;
|
81
81
|
}
|
82
82
|
|
83
83
|
|
84
|
-
std::ostream& operator<<(std::ostream& os,
|
84
|
+
std::ostream& operator<<(std::ostream& os, SimpleSequence_Selector& compoundSelector) {
|
85
85
|
for (size_t i = 0, L = compoundSelector.length(); i < L; ++i) {
|
86
86
|
if (i > 0) os << ", ";
|
87
87
|
os << compoundSelector[i]->to_string();
|
@@ -94,7 +94,7 @@ namespace Sass {
|
|
94
94
|
return os;
|
95
95
|
}
|
96
96
|
|
97
|
-
// Print a string representation of a
|
97
|
+
// Print a string representation of a SimpleSequence_Selector
|
98
98
|
static void printSimpleSelector(Simple_Selector* pSimpleSelector, const char* message=NULL, bool newline=true) {
|
99
99
|
|
100
100
|
if (message) {
|
@@ -112,13 +112,13 @@ namespace Sass {
|
|
112
112
|
}
|
113
113
|
}
|
114
114
|
|
115
|
-
// Print a string representation of a
|
116
|
-
typedef std::pair<
|
115
|
+
// Print a string representation of a SimpleSequence_Selector
|
116
|
+
typedef std::pair<SimpleSequence_Selector*, Sequence_Selector*> SelsNewSeqPair;
|
117
117
|
typedef std::vector<SelsNewSeqPair> SelsNewSeqPairCollection;
|
118
118
|
|
119
119
|
|
120
|
-
// Print a string representation of a
|
121
|
-
static void printCompoundSelector(
|
120
|
+
// Print a string representation of a SimpleSequence_Selector
|
121
|
+
static void printCompoundSelector(SimpleSequence_Selector* pCompoundSelector, const char* message=NULL, bool newline=true) {
|
122
122
|
|
123
123
|
if (message) {
|
124
124
|
std::cerr << message;
|
@@ -136,13 +136,13 @@ namespace Sass {
|
|
136
136
|
}
|
137
137
|
|
138
138
|
|
139
|
-
std::ostream& operator<<(std::ostream& os,
|
139
|
+
std::ostream& operator<<(std::ostream& os, Sequence_Selector& complexSelector) {
|
140
140
|
|
141
141
|
os << "[";
|
142
|
-
|
142
|
+
Sequence_Selector* pIter = &complexSelector;
|
143
143
|
bool first = true;
|
144
144
|
while (pIter) {
|
145
|
-
if (pIter->combinator() !=
|
145
|
+
if (pIter->combinator() != Sequence_Selector::ANCESTOR_OF) {
|
146
146
|
if (!first) {
|
147
147
|
os << ", ";
|
148
148
|
}
|
@@ -169,8 +169,8 @@ namespace Sass {
|
|
169
169
|
}
|
170
170
|
|
171
171
|
|
172
|
-
// Print a string representation of a
|
173
|
-
static void printComplexSelector(
|
172
|
+
// Print a string representation of a Sequence_Selector
|
173
|
+
static void printComplexSelector(Sequence_Selector* pComplexSelector, const char* message=NULL, bool newline=true) {
|
174
174
|
|
175
175
|
if (message) {
|
176
176
|
std::cerr << message;
|
@@ -201,8 +201,8 @@ namespace Sass {
|
|
201
201
|
std::cerr << ", ";
|
202
202
|
}
|
203
203
|
std::cerr << "[";
|
204
|
-
|
205
|
-
|
204
|
+
SimpleSequence_Selector* pSels = pair.first;
|
205
|
+
Sequence_Selector* pNewSelector = pair.second;
|
206
206
|
std::cerr << "[" << *pSels << "], ";
|
207
207
|
printComplexSelector(pNewSelector, NULL, false);
|
208
208
|
}
|
@@ -225,7 +225,7 @@ namespace Sass {
|
|
225
225
|
typedef std::deque<std::string> SourceStrings;
|
226
226
|
SourceStrings sourceStrings;
|
227
227
|
for (SourcesSet::iterator iterator = sources.begin(), iteratorEnd = sources.end(); iterator != iteratorEnd; ++iterator) {
|
228
|
-
|
228
|
+
Sequence_Selector* pSource = *iterator;
|
229
229
|
std::stringstream sstream;
|
230
230
|
sstream << complexSelectorToNode(pSource, ctx);
|
231
231
|
sourceStrings.push_back(sstream.str());
|
@@ -254,8 +254,8 @@ namespace Sass {
|
|
254
254
|
os << "SUBSET_MAP_ENTRIES[";
|
255
255
|
|
256
256
|
for (SubsetMapEntries::iterator iterator = entries.begin(), endIterator = entries.end(); iterator != endIterator; ++iterator) {
|
257
|
-
|
258
|
-
|
257
|
+
Sequence_Selector* pExtComplexSelector = iterator->first; // The selector up to where the @extend is (ie, the thing to merge)
|
258
|
+
SimpleSequence_Selector* pExtCompoundSelector = iterator->second; // The stuff after the @extend
|
259
259
|
|
260
260
|
if (iterator != entries.begin()) {
|
261
261
|
os << ", ";
|
@@ -287,17 +287,17 @@ namespace Sass {
|
|
287
287
|
}
|
288
288
|
#endif
|
289
289
|
|
290
|
-
static bool parentSuperselector(
|
291
|
-
// TODO: figure out a better way to create a
|
290
|
+
static bool parentSuperselector(Sequence_Selector* pOne, Sequence_Selector* pTwo, Context& ctx) {
|
291
|
+
// TODO: figure out a better way to create a Sequence_Selector from scratch
|
292
292
|
// TODO: There's got to be a better way. This got ugly quick...
|
293
293
|
Position noPosition(-1, -1, -1);
|
294
|
-
|
295
|
-
|
294
|
+
Element_Selector fakeParent(ParserState("[FAKE]"), "temp");
|
295
|
+
SimpleSequence_Selector fakeHead(ParserState("[FAKE]"), 1 /*size*/);
|
296
296
|
fakeHead.elements().push_back(&fakeParent);
|
297
|
-
|
297
|
+
Sequence_Selector fakeParentContainer(ParserState("[FAKE]"), Sequence_Selector::ANCESTOR_OF, &fakeHead /*head*/, NULL /*tail*/);
|
298
298
|
|
299
|
-
pOne->set_innermost(&fakeParentContainer,
|
300
|
-
pTwo->set_innermost(&fakeParentContainer,
|
299
|
+
pOne->set_innermost(&fakeParentContainer, Sequence_Selector::ANCESTOR_OF);
|
300
|
+
pTwo->set_innermost(&fakeParentContainer, Sequence_Selector::ANCESTOR_OF);
|
301
301
|
|
302
302
|
bool isSuperselector = pOne->is_superselector_of(pTwo);
|
303
303
|
|
@@ -318,7 +318,7 @@ namespace Sass {
|
|
318
318
|
Node result = Node::createCollection();
|
319
319
|
|
320
320
|
for (ComplexSelectorDeque::const_iterator iter = deque.begin(), iterEnd = deque.end(); iter != iterEnd; iter++) {
|
321
|
-
|
321
|
+
Sequence_Selector* pChild = *iter;
|
322
322
|
result.collection()->push_back(complexSelectorToNode(pChild, ctx));
|
323
323
|
}
|
324
324
|
|
@@ -331,7 +331,7 @@ namespace Sass {
|
|
331
331
|
|
332
332
|
Context& mCtx;
|
333
333
|
|
334
|
-
bool operator()(
|
334
|
+
bool operator()(Sequence_Selector* pOne, Sequence_Selector* pTwo, Sequence_Selector*& pOut) const {
|
335
335
|
/*
|
336
336
|
This code is based on the following block from ruby sass' subweave
|
337
337
|
do |s1, s2|
|
@@ -347,7 +347,7 @@ namespace Sass {
|
|
347
347
|
return true;
|
348
348
|
}
|
349
349
|
|
350
|
-
if (pOne->combinator() !=
|
350
|
+
if (pOne->combinator() != Sequence_Selector::ANCESTOR_OF || pTwo->combinator() != Sequence_Selector::ANCESTOR_OF) {
|
351
351
|
return false;
|
352
352
|
}
|
353
353
|
|
@@ -382,7 +382,7 @@ namespace Sass {
|
|
382
382
|
}
|
383
383
|
|
384
384
|
|
385
|
-
|
385
|
+
Sequence_Selector* pCompareOut = NULL;
|
386
386
|
if (comparator(x[i], y[j], pCompareOut)) {
|
387
387
|
DEBUG_PRINTLN(LCS, "RETURNING AFTER ELEM COMPARE")
|
388
388
|
lcs_backtrace(c, x, y, i - 1, j - 1, comparator, out);
|
@@ -419,7 +419,7 @@ namespace Sass {
|
|
419
419
|
|
420
420
|
for (size_t i = 1; i < x.size(); i++) {
|
421
421
|
for (size_t j = 1; j < y.size(); j++) {
|
422
|
-
|
422
|
+
Sequence_Selector* pCompareOut = NULL;
|
423
423
|
|
424
424
|
if (comparator(x[i], y[j], pCompareOut)) {
|
425
425
|
c[i][j] = c[i - 1][j - 1] + 1;
|
@@ -559,7 +559,7 @@ namespace Sass {
|
|
559
559
|
for (NodeDeque::iterator seqs1Iter = seqs1.collection()->begin(), seqs1EndIter = seqs1.collection()->end(); seqs1Iter != seqs1EndIter; ++seqs1Iter) {
|
560
560
|
Node& seq1 = *seqs1Iter;
|
561
561
|
|
562
|
-
|
562
|
+
Sequence_Selector* pSeq1 = nodeToComplexSelector(seq1, ctx);
|
563
563
|
|
564
564
|
// Compute the maximum specificity. This requires looking at the "sources" of the sequence. See SimpleSequence.sources in the ruby code
|
565
565
|
// for a good description of sources.
|
@@ -576,7 +576,7 @@ namespace Sass {
|
|
576
576
|
DEBUG_EXEC(TRIM, printSourcesSet(sources, ctx, "TRIM SOURCES: "))
|
577
577
|
|
578
578
|
for (SourcesSet::iterator sourcesSetIterator = sources.begin(), sourcesSetIteratorEnd = sources.end(); sourcesSetIterator != sourcesSetIteratorEnd; ++sourcesSetIterator) {
|
579
|
-
const
|
579
|
+
const Sequence_Selector* const pCurrentSelector = *sourcesSetIterator;
|
580
580
|
maxSpecificity = std::max(maxSpecificity, pCurrentSelector->specificity());
|
581
581
|
}
|
582
582
|
|
@@ -606,7 +606,7 @@ namespace Sass {
|
|
606
606
|
for (NodeDeque::iterator seqs2Iter = seqs2.collection()->begin(), seqs2IterEnd = seqs2.collection()->end(); seqs2Iter != seqs2IterEnd; ++seqs2Iter) {
|
607
607
|
Node& seq2 = *seqs2Iter;
|
608
608
|
|
609
|
-
|
609
|
+
Sequence_Selector* pSeq2 = nodeToComplexSelector(seq2, ctx);
|
610
610
|
|
611
611
|
DEBUG_PRINTLN(TRIM, "SEQ2 SPEC: " << pSeq2->specificity())
|
612
612
|
DEBUG_PRINTLN(TRIM, "IS SPEC: " << pSeq2->specificity() << " >= " << maxSpecificity << " " << (pSeq2->specificity() >= maxSpecificity ? "true" : "false"))
|
@@ -651,18 +651,18 @@ namespace Sass {
|
|
651
651
|
|
652
652
|
|
653
653
|
static bool parentSuperselector(const Node& one, const Node& two, Context& ctx) {
|
654
|
-
// TODO: figure out a better way to create a
|
654
|
+
// TODO: figure out a better way to create a Sequence_Selector from scratch
|
655
655
|
// TODO: There's got to be a better way. This got ugly quick...
|
656
656
|
Position noPosition(-1, -1, -1);
|
657
|
-
|
658
|
-
|
657
|
+
Element_Selector fakeParent(ParserState("[FAKE]"), "temp");
|
658
|
+
SimpleSequence_Selector fakeHead(ParserState("[FAKE]"), 1 /*size*/);
|
659
659
|
fakeHead.elements().push_back(&fakeParent);
|
660
|
-
|
660
|
+
Sequence_Selector fakeParentContainer(ParserState("[FAKE]"), Sequence_Selector::ANCESTOR_OF, &fakeHead /*head*/, NULL /*tail*/);
|
661
661
|
|
662
|
-
|
663
|
-
pOneWithFakeParent->set_innermost(&fakeParentContainer,
|
664
|
-
|
665
|
-
pTwoWithFakeParent->set_innermost(&fakeParentContainer,
|
662
|
+
Sequence_Selector* pOneWithFakeParent = nodeToComplexSelector(one, ctx);
|
663
|
+
pOneWithFakeParent->set_innermost(&fakeParentContainer, Sequence_Selector::ANCESTOR_OF);
|
664
|
+
Sequence_Selector* pTwoWithFakeParent = nodeToComplexSelector(two, ctx);
|
665
|
+
pTwoWithFakeParent->set_innermost(&fakeParentContainer, Sequence_Selector::ANCESTOR_OF);
|
666
666
|
|
667
667
|
return pOneWithFakeParent->is_superselector_of(pTwoWithFakeParent);
|
668
668
|
}
|
@@ -970,7 +970,7 @@ namespace Sass {
|
|
970
970
|
Node sel2 = seq2.collection()->back();
|
971
971
|
seq2.collection()->pop_back();
|
972
972
|
|
973
|
-
if (op1.combinator() ==
|
973
|
+
if (op1.combinator() == Sequence_Selector::PRECEDES && op2.combinator() == Sequence_Selector::PRECEDES) {
|
974
974
|
|
975
975
|
if (sel1.selector()->is_superselector_of(sel2.selector())) {
|
976
976
|
|
@@ -987,9 +987,9 @@ namespace Sass {
|
|
987
987
|
DEBUG_PRINTLN(ALL, "sel1: " << sel1)
|
988
988
|
DEBUG_PRINTLN(ALL, "sel2: " << sel2)
|
989
989
|
|
990
|
-
|
990
|
+
Sequence_Selector* pMergedWrapper = sel1.selector()->clone(ctx); // Clone the Sequence_Selector to get back to something we can transform to a node once we replace the head with the unification result
|
991
991
|
// TODO: does subject matter? Ruby: return unless merged = sel1.unify(sel2.members, sel2.subject?)
|
992
|
-
|
992
|
+
SimpleSequence_Selector* pMerged = sel1.selector()->head()->unify_with(sel2.selector()->head(), ctx);
|
993
993
|
pMergedWrapper->head(pMerged);
|
994
994
|
|
995
995
|
DEBUG_EXEC(ALL, printCompoundSelector(pMerged, "MERGED: "))
|
@@ -998,22 +998,22 @@ namespace Sass {
|
|
998
998
|
|
999
999
|
Node firstPerm = Node::createCollection();
|
1000
1000
|
firstPerm.collection()->push_back(sel1);
|
1001
|
-
firstPerm.collection()->push_back(Node::createCombinator(
|
1001
|
+
firstPerm.collection()->push_back(Node::createCombinator(Sequence_Selector::PRECEDES));
|
1002
1002
|
firstPerm.collection()->push_back(sel2);
|
1003
|
-
firstPerm.collection()->push_back(Node::createCombinator(
|
1003
|
+
firstPerm.collection()->push_back(Node::createCombinator(Sequence_Selector::PRECEDES));
|
1004
1004
|
newRes.collection()->push_back(firstPerm);
|
1005
1005
|
|
1006
1006
|
Node secondPerm = Node::createCollection();
|
1007
1007
|
secondPerm.collection()->push_back(sel2);
|
1008
|
-
secondPerm.collection()->push_back(Node::createCombinator(
|
1008
|
+
secondPerm.collection()->push_back(Node::createCombinator(Sequence_Selector::PRECEDES));
|
1009
1009
|
secondPerm.collection()->push_back(sel1);
|
1010
|
-
secondPerm.collection()->push_back(Node::createCombinator(
|
1010
|
+
secondPerm.collection()->push_back(Node::createCombinator(Sequence_Selector::PRECEDES));
|
1011
1011
|
newRes.collection()->push_back(secondPerm);
|
1012
1012
|
|
1013
1013
|
if (pMerged) {
|
1014
1014
|
Node mergedPerm = Node::createCollection();
|
1015
1015
|
mergedPerm.collection()->push_back(Node::createSelector(pMergedWrapper, ctx));
|
1016
|
-
mergedPerm.collection()->push_back(Node::createCombinator(
|
1016
|
+
mergedPerm.collection()->push_back(Node::createCombinator(Sequence_Selector::PRECEDES));
|
1017
1017
|
newRes.collection()->push_back(mergedPerm);
|
1018
1018
|
}
|
1019
1019
|
|
@@ -1023,13 +1023,13 @@ namespace Sass {
|
|
1023
1023
|
|
1024
1024
|
}
|
1025
1025
|
|
1026
|
-
} else if (((op1.combinator() ==
|
1026
|
+
} else if (((op1.combinator() == Sequence_Selector::PRECEDES && op2.combinator() == Sequence_Selector::ADJACENT_TO)) || ((op1.combinator() == Sequence_Selector::ADJACENT_TO && op2.combinator() == Sequence_Selector::PRECEDES))) {
|
1027
1027
|
|
1028
1028
|
Node tildeSel = sel1;
|
1029
1029
|
Node tildeOp = op1;
|
1030
1030
|
Node plusSel = sel2;
|
1031
1031
|
Node plusOp = op2;
|
1032
|
-
if (op1.combinator() !=
|
1032
|
+
if (op1.combinator() != Sequence_Selector::PRECEDES) {
|
1033
1033
|
tildeSel = sel2;
|
1034
1034
|
tildeOp = op2;
|
1035
1035
|
plusSel = sel1;
|
@@ -1046,9 +1046,9 @@ namespace Sass {
|
|
1046
1046
|
DEBUG_PRINTLN(ALL, "PLUS SEL: " << plusSel)
|
1047
1047
|
DEBUG_PRINTLN(ALL, "TILDE SEL: " << tildeSel)
|
1048
1048
|
|
1049
|
-
|
1049
|
+
Sequence_Selector* pMergedWrapper = plusSel.selector()->clone(ctx); // Clone the Sequence_Selector to get back to something we can transform to a node once we replace the head with the unification result
|
1050
1050
|
// TODO: does subject matter? Ruby: merged = plus_sel.unify(tilde_sel.members, tilde_sel.subject?)
|
1051
|
-
|
1051
|
+
SimpleSequence_Selector* pMerged = plusSel.selector()->head()->unify_with(tildeSel.selector()->head(), ctx);
|
1052
1052
|
pMergedWrapper->head(pMerged);
|
1053
1053
|
|
1054
1054
|
DEBUG_EXEC(ALL, printCompoundSelector(pMerged, "MERGED: "))
|
@@ -1057,15 +1057,15 @@ namespace Sass {
|
|
1057
1057
|
|
1058
1058
|
Node firstPerm = Node::createCollection();
|
1059
1059
|
firstPerm.collection()->push_back(tildeSel);
|
1060
|
-
firstPerm.collection()->push_back(Node::createCombinator(
|
1060
|
+
firstPerm.collection()->push_back(Node::createCombinator(Sequence_Selector::PRECEDES));
|
1061
1061
|
firstPerm.collection()->push_back(plusSel);
|
1062
|
-
firstPerm.collection()->push_back(Node::createCombinator(
|
1062
|
+
firstPerm.collection()->push_back(Node::createCombinator(Sequence_Selector::ADJACENT_TO));
|
1063
1063
|
newRes.collection()->push_back(firstPerm);
|
1064
1064
|
|
1065
1065
|
if (pMerged) {
|
1066
1066
|
Node mergedPerm = Node::createCollection();
|
1067
1067
|
mergedPerm.collection()->push_back(Node::createSelector(pMergedWrapper, ctx));
|
1068
|
-
mergedPerm.collection()->push_back(Node::createCombinator(
|
1068
|
+
mergedPerm.collection()->push_back(Node::createCombinator(Sequence_Selector::ADJACENT_TO));
|
1069
1069
|
newRes.collection()->push_back(mergedPerm);
|
1070
1070
|
}
|
1071
1071
|
|
@@ -1074,7 +1074,7 @@ namespace Sass {
|
|
1074
1074
|
DEBUG_PRINTLN(ALL, "RESULT: " << res)
|
1075
1075
|
|
1076
1076
|
}
|
1077
|
-
} else if (op1.combinator() ==
|
1077
|
+
} else if (op1.combinator() == Sequence_Selector::PARENT_OF && (op2.combinator() == Sequence_Selector::PRECEDES || op2.combinator() == Sequence_Selector::ADJACENT_TO)) {
|
1078
1078
|
|
1079
1079
|
res.collection()->push_front(op2);
|
1080
1080
|
res.collection()->push_front(sel2);
|
@@ -1082,7 +1082,7 @@ namespace Sass {
|
|
1082
1082
|
seq1.collection()->push_back(sel1);
|
1083
1083
|
seq1.collection()->push_back(op1);
|
1084
1084
|
|
1085
|
-
} else if (op2.combinator() ==
|
1085
|
+
} else if (op2.combinator() == Sequence_Selector::PARENT_OF && (op1.combinator() == Sequence_Selector::PRECEDES || op1.combinator() == Sequence_Selector::ADJACENT_TO)) {
|
1086
1086
|
|
1087
1087
|
res.collection()->push_front(op1);
|
1088
1088
|
res.collection()->push_front(sel1);
|
@@ -1095,9 +1095,9 @@ namespace Sass {
|
|
1095
1095
|
DEBUG_PRINTLN(ALL, "sel1: " << sel1)
|
1096
1096
|
DEBUG_PRINTLN(ALL, "sel2: " << sel2)
|
1097
1097
|
|
1098
|
-
|
1098
|
+
Sequence_Selector* pMergedWrapper = sel1.selector()->clone(ctx); // Clone the Sequence_Selector to get back to something we can transform to a node once we replace the head with the unification result
|
1099
1099
|
// TODO: does subject matter? Ruby: return unless merged = sel1.unify(sel2.members, sel2.subject?)
|
1100
|
-
|
1100
|
+
SimpleSequence_Selector* pMerged = sel1.selector()->head()->unify_with(sel2.selector()->head(), ctx);
|
1101
1101
|
pMergedWrapper->head(pMerged);
|
1102
1102
|
|
1103
1103
|
DEBUG_EXEC(ALL, printCompoundSelector(pMerged, "MERGED: "))
|
@@ -1121,7 +1121,7 @@ namespace Sass {
|
|
1121
1121
|
|
1122
1122
|
Node op1 = ops1.collection()->front();
|
1123
1123
|
|
1124
|
-
if (op1.combinator() ==
|
1124
|
+
if (op1.combinator() == Sequence_Selector::PARENT_OF && !seq2.collection()->empty() && seq2.collection()->back().selector()->is_superselector_of(seq1.collection()->back().selector())) {
|
1125
1125
|
seq2.collection()->pop_back();
|
1126
1126
|
}
|
1127
1127
|
|
@@ -1136,7 +1136,7 @@ namespace Sass {
|
|
1136
1136
|
|
1137
1137
|
Node op2 = ops2.collection()->front();
|
1138
1138
|
|
1139
|
-
if (op2.combinator() ==
|
1139
|
+
if (op2.combinator() == Sequence_Selector::PARENT_OF && !seq1.collection()->empty() && seq1.collection()->back().selector()->is_superselector_of(seq2.collection()->back().selector())) {
|
1140
1140
|
seq1.collection()->pop_back();
|
1141
1141
|
}
|
1142
1142
|
|
@@ -1509,10 +1509,10 @@ namespace Sass {
|
|
1509
1509
|
// This forward declaration is needed since extendComplexSelector calls extendCompoundSelector, which may recursively
|
1510
1510
|
// call extendComplexSelector again.
|
1511
1511
|
static Node extendComplexSelector(
|
1512
|
-
|
1512
|
+
Sequence_Selector* pComplexSelector,
|
1513
1513
|
Context& ctx,
|
1514
1514
|
ExtensionSubsetMap& subset_map,
|
1515
|
-
std::set<
|
1515
|
+
std::set<SimpleSequence_Selector> seen, bool isReplace, bool isOriginal);
|
1516
1516
|
|
1517
1517
|
|
1518
1518
|
|
@@ -1532,15 +1532,15 @@ namespace Sass {
|
|
1532
1532
|
class GroupByToAFunctor {
|
1533
1533
|
public:
|
1534
1534
|
KeyType operator()(ExtensionPair& extPair) const {
|
1535
|
-
|
1535
|
+
Sequence_Selector* pSelector = extPair.first;
|
1536
1536
|
return *pSelector;
|
1537
1537
|
}
|
1538
1538
|
};
|
1539
1539
|
static Node extendCompoundSelector(
|
1540
|
-
|
1540
|
+
SimpleSequence_Selector* pSelector,
|
1541
1541
|
Context& ctx,
|
1542
1542
|
ExtensionSubsetMap& subset_map,
|
1543
|
-
std::set<
|
1543
|
+
std::set<SimpleSequence_Selector> seen, bool isReplace) {
|
1544
1544
|
|
1545
1545
|
DEBUG_EXEC(EXTEND_COMPOUND, printCompoundSelector(pSelector, "EXTEND COMPOUND: "))
|
1546
1546
|
// TODO: Ruby has another loop here to skip certain members?
|
@@ -1550,13 +1550,13 @@ namespace Sass {
|
|
1550
1550
|
|
1551
1551
|
SubsetMapEntries entries = subset_map.get_v(pSelector->to_str_vec());
|
1552
1552
|
|
1553
|
-
typedef std::vector<std::pair<
|
1553
|
+
typedef std::vector<std::pair<Sequence_Selector, std::vector<ExtensionPair> > > GroupedByToAResult;
|
1554
1554
|
|
1555
|
-
GroupByToAFunctor<
|
1555
|
+
GroupByToAFunctor<Sequence_Selector> extPairKeyFunctor;
|
1556
1556
|
GroupedByToAResult arr;
|
1557
1557
|
group_by_to_a(entries, extPairKeyFunctor, arr);
|
1558
1558
|
|
1559
|
-
typedef std::pair<
|
1559
|
+
typedef std::pair<SimpleSequence_Selector*, Sequence_Selector*> SelsNewSeqPair;
|
1560
1560
|
typedef std::vector<SelsNewSeqPair> SelsNewSeqPairCollection;
|
1561
1561
|
|
1562
1562
|
|
@@ -1564,18 +1564,18 @@ namespace Sass {
|
|
1564
1564
|
|
1565
1565
|
|
1566
1566
|
for (GroupedByToAResult::iterator groupedIter = arr.begin(), groupedIterEnd = arr.end(); groupedIter != groupedIterEnd; groupedIter++) {
|
1567
|
-
std::pair<
|
1567
|
+
std::pair<Sequence_Selector, std::vector<ExtensionPair> >& groupedPair = *groupedIter;
|
1568
1568
|
|
1569
|
-
|
1569
|
+
Sequence_Selector& seq = groupedPair.first;
|
1570
1570
|
std::vector<ExtensionPair>& group = groupedPair.second;
|
1571
1571
|
|
1572
1572
|
DEBUG_EXEC(EXTEND_COMPOUND, printComplexSelector(&seq, "SEQ: "))
|
1573
1573
|
|
1574
1574
|
|
1575
|
-
|
1575
|
+
SimpleSequence_Selector* pSels = SASS_MEMORY_NEW(ctx.mem, SimpleSequence_Selector, pSelector->pstate());
|
1576
1576
|
for (std::vector<ExtensionPair>::iterator groupIter = group.begin(), groupIterEnd = group.end(); groupIter != groupIterEnd; groupIter++) {
|
1577
1577
|
ExtensionPair& pair = *groupIter;
|
1578
|
-
|
1578
|
+
SimpleSequence_Selector* pCompound = pair.second;
|
1579
1579
|
for (size_t index = 0; index < pCompound->length(); index++) {
|
1580
1580
|
Simple_Selector* pSimpleSelector = (*pCompound)[index];
|
1581
1581
|
(*pSels) << pSimpleSelector;
|
@@ -1585,21 +1585,21 @@ namespace Sass {
|
|
1585
1585
|
|
1586
1586
|
DEBUG_EXEC(EXTEND_COMPOUND, printCompoundSelector(pSels, "SELS: "))
|
1587
1587
|
|
1588
|
-
|
1589
|
-
|
1588
|
+
Sequence_Selector* pExtComplexSelector = &seq; // The selector up to where the @extend is (ie, the thing to merge)
|
1589
|
+
SimpleSequence_Selector* pExtCompoundSelector = pSels; // All the simple selectors to be replaced from the current compound selector from all extensions
|
1590
1590
|
|
1591
|
-
// TODO: This can return a
|
1591
|
+
// TODO: This can return a SimpleSequence_Selector with no elements. Should that just be returning NULL?
|
1592
1592
|
// RUBY: self_without_sel = Sass::Util.array_minus(members, sels)
|
1593
|
-
|
1593
|
+
SimpleSequence_Selector* pSelectorWithoutExtendSelectors = pSelector->minus(pExtCompoundSelector, ctx);
|
1594
1594
|
|
1595
1595
|
DEBUG_EXEC(EXTEND_COMPOUND, printCompoundSelector(pSelector, "MEMBERS: "))
|
1596
1596
|
DEBUG_EXEC(EXTEND_COMPOUND, printCompoundSelector(pSelectorWithoutExtendSelectors, "SELF_WO_SEL: "))
|
1597
1597
|
|
1598
|
-
|
1599
|
-
|
1598
|
+
SimpleSequence_Selector* pInnermostCompoundSelector = pExtComplexSelector->last()->head();
|
1599
|
+
SimpleSequence_Selector* pUnifiedSelector = NULL;
|
1600
1600
|
|
1601
1601
|
if (!pInnermostCompoundSelector) {
|
1602
|
-
pInnermostCompoundSelector = SASS_MEMORY_NEW(ctx.mem,
|
1602
|
+
pInnermostCompoundSelector = SASS_MEMORY_NEW(ctx.mem, SimpleSequence_Selector, pSelector->pstate());
|
1603
1603
|
}
|
1604
1604
|
|
1605
1605
|
pUnifiedSelector = pInnermostCompoundSelector->unify_with(pSelectorWithoutExtendSelectors, ctx);
|
@@ -1618,14 +1618,14 @@ namespace Sass {
|
|
1618
1618
|
// next if group.map {|e, _| check_directives_match!(e, parent_directives)}.none?
|
1619
1619
|
|
1620
1620
|
// TODO: This seems a little fishy to me. See if it causes any problems. From the ruby, we should be able to just
|
1621
|
-
// get rid of the last
|
1622
|
-
// complex is that
|
1621
|
+
// get rid of the last SimpleSequence_Selector and replace it with this one. I think the reason this code is more
|
1622
|
+
// complex is that Sequence_Selector contains a combinator, but in ruby combinators have already been filtered
|
1623
1623
|
// out and aren't operated on.
|
1624
|
-
|
1624
|
+
Sequence_Selector* pNewSelector = pExtComplexSelector->cloneFully(ctx); // ->first();
|
1625
1625
|
|
1626
|
-
|
1626
|
+
Sequence_Selector* pNewInnerMost = SASS_MEMORY_NEW(ctx.mem, Sequence_Selector, pSelector->pstate(), Sequence_Selector::ANCESTOR_OF, pUnifiedSelector, NULL);
|
1627
1627
|
|
1628
|
-
|
1628
|
+
Sequence_Selector::Combinator combinator = pNewSelector->clear_innermost();
|
1629
1629
|
pNewSelector->set_innermost(pNewInnerMost, combinator);
|
1630
1630
|
|
1631
1631
|
#ifdef DEBUG
|
@@ -1642,7 +1642,7 @@ namespace Sass {
|
|
1642
1642
|
|
1643
1643
|
|
1644
1644
|
// if (pSelector && pSelector->has_line_feed()) pNewInnerMost->has_line_feed(true);
|
1645
|
-
// Set the sources on our new
|
1645
|
+
// Set the sources on our new Sequence_Selector to the sources of this simple sequence plus the thing we're extending.
|
1646
1646
|
DEBUG_PRINTLN(EXTEND_COMPOUND, "SOURCES SETTING ON NEW SEQ: " << complexSelectorToNode(pNewSelector, ctx))
|
1647
1647
|
|
1648
1648
|
DEBUG_EXEC(EXTEND_COMPOUND, SourcesSet oldSet = pNewSelector->sources(); printSourcesSet(oldSet, ctx, "SOURCES NEW SEQ BEGIN: "))
|
@@ -1669,8 +1669,8 @@ namespace Sass {
|
|
1669
1669
|
for (SelsNewSeqPairCollection::iterator holderIter = holder.begin(), holderIterEnd = holder.end(); holderIter != holderIterEnd; holderIter++) {
|
1670
1670
|
SelsNewSeqPair& pair = *holderIter;
|
1671
1671
|
|
1672
|
-
|
1673
|
-
|
1672
|
+
SimpleSequence_Selector* pSels = pair.first;
|
1673
|
+
Sequence_Selector* pNewSelector = pair.second;
|
1674
1674
|
|
1675
1675
|
|
1676
1676
|
// RUBY??: next [] if seen.include?(sels)
|
@@ -1679,7 +1679,7 @@ namespace Sass {
|
|
1679
1679
|
}
|
1680
1680
|
|
1681
1681
|
|
1682
|
-
std::set<
|
1682
|
+
std::set<SimpleSequence_Selector> recurseSeen(seen);
|
1683
1683
|
recurseSeen.insert(*pSels);
|
1684
1684
|
|
1685
1685
|
|
@@ -1709,33 +1709,19 @@ namespace Sass {
|
|
1709
1709
|
|
1710
1710
|
|
1711
1711
|
static bool complexSelectorHasExtension(
|
1712
|
-
|
1712
|
+
Sequence_Selector* pComplexSelector,
|
1713
1713
|
Context& ctx,
|
1714
|
-
ExtensionSubsetMap& subset_map
|
1714
|
+
ExtensionSubsetMap& subset_map,
|
1715
|
+
std::set<SimpleSequence_Selector>& seen) {
|
1715
1716
|
|
1716
1717
|
bool hasExtension = false;
|
1717
1718
|
|
1718
|
-
|
1719
|
+
Sequence_Selector* pIter = pComplexSelector;
|
1719
1720
|
|
1720
1721
|
while (!hasExtension && pIter) {
|
1721
|
-
|
1722
|
+
SimpleSequence_Selector* pHead = pIter->head();
|
1722
1723
|
|
1723
1724
|
if (pHead) {
|
1724
|
-
for (Simple_Selector* pSimple : *pHead) {
|
1725
|
-
if (Wrapped_Selector* ws = dynamic_cast<Wrapped_Selector*>(pSimple)) {
|
1726
|
-
if (Selector_List* sl = dynamic_cast<Selector_List*>(ws->selector())) {
|
1727
|
-
for (Complex_Selector* cs : sl->elements()) {
|
1728
|
-
while (cs) {
|
1729
|
-
if (complexSelectorHasExtension(cs, ctx, subset_map)) {
|
1730
|
-
hasExtension = true;
|
1731
|
-
break;
|
1732
|
-
}
|
1733
|
-
cs = cs->tail();
|
1734
|
-
}
|
1735
|
-
}
|
1736
|
-
}
|
1737
|
-
}
|
1738
|
-
}
|
1739
1725
|
SubsetMapEntries entries = subset_map.get_v(pHead->to_str_vec());
|
1740
1726
|
for (ExtensionPair ext : entries) {
|
1741
1727
|
// check if both selectors have the same media block parent
|
@@ -1783,10 +1769,10 @@ namespace Sass {
|
|
1783
1769
|
next [[sseq_or_op]] unless sseq_or_op.is_a?(SimpleSequence)
|
1784
1770
|
*/
|
1785
1771
|
static Node extendComplexSelector(
|
1786
|
-
|
1772
|
+
Sequence_Selector* pComplexSelector,
|
1787
1773
|
Context& ctx,
|
1788
1774
|
ExtensionSubsetMap& subset_map,
|
1789
|
-
std::set<
|
1775
|
+
std::set<SimpleSequence_Selector> seen, bool isReplace, bool isOriginal) {
|
1790
1776
|
|
1791
1777
|
Node complexSelector = complexSelectorToNode(pComplexSelector, ctx);
|
1792
1778
|
DEBUG_PRINTLN(EXTEND_COMPLEX, "EXTEND COMPLEX: " << complexSelector)
|
@@ -1806,7 +1792,7 @@ namespace Sass {
|
|
1806
1792
|
// RUBY: next [[sseq_or_op]] unless sseq_or_op.is_a?(SimpleSequence)
|
1807
1793
|
if (!sseqOrOp.isSelector()) {
|
1808
1794
|
// Wrap our Combinator in two collections to match ruby. This is essentially making a collection Node
|
1809
|
-
// with one collection child. The collection child represents a
|
1795
|
+
// with one collection child. The collection child represents a Sequence_Selector that is only a combinator.
|
1810
1796
|
Node outer = Node::createCollection();
|
1811
1797
|
Node inner = Node::createCollection();
|
1812
1798
|
outer.collection()->push_back(inner);
|
@@ -1815,7 +1801,7 @@ namespace Sass {
|
|
1815
1801
|
continue;
|
1816
1802
|
}
|
1817
1803
|
|
1818
|
-
|
1804
|
+
SimpleSequence_Selector* pCompoundSelector = sseqOrOp.selector()->head();
|
1819
1805
|
|
1820
1806
|
// RUBY: extended = sseq_or_op.do_extend(extends, parent_directives, replace, seen)
|
1821
1807
|
Node extended = extendCompoundSelector(pCompoundSelector, ctx, subset_map, seen, isReplace);
|
@@ -1823,9 +1809,9 @@ namespace Sass {
|
|
1823
1809
|
DEBUG_PRINTLN(EXTEND_COMPLEX, "EXTENDED: " << extended)
|
1824
1810
|
|
1825
1811
|
|
1826
|
-
// Prepend the
|
1812
|
+
// Prepend the SimpleSequence_Selector based on the choices logic; choices seems to be extend but with an ruby Array instead of a Sequence
|
1827
1813
|
// due to the member mapping: choices = extended.map {|seq| seq.members}
|
1828
|
-
|
1814
|
+
Sequence_Selector* pJustCurrentCompoundSelector = sseqOrOp.selector();
|
1829
1815
|
|
1830
1816
|
// RUBY: extended.first.add_sources!([self]) if original && !has_placeholder?
|
1831
1817
|
if (isOriginal && !pComplexSelector->has_placeholder()) {
|
@@ -1839,7 +1825,7 @@ namespace Sass {
|
|
1839
1825
|
for (NodeDeque::iterator iterator = extended.collection()->begin(), endIterator = extended.collection()->end();
|
1840
1826
|
iterator != endIterator; ++iterator) {
|
1841
1827
|
Node& childNode = *iterator;
|
1842
|
-
|
1828
|
+
Sequence_Selector* pExtensionSelector = nodeToComplexSelector(childNode, ctx);
|
1843
1829
|
if (pExtensionSelector->is_superselector_of(pJustCurrentCompoundSelector)) {
|
1844
1830
|
isSuperselector = true;
|
1845
1831
|
break;
|
@@ -1906,33 +1892,40 @@ namespace Sass {
|
|
1906
1892
|
/*
|
1907
1893
|
This is the equivalent of ruby's CommaSequence.do_extend.
|
1908
1894
|
*/
|
1909
|
-
|
1895
|
+
CommaSequence_Selector* Extend::extendSelectorList(CommaSequence_Selector* pSelectorList, Context& ctx, ExtensionSubsetMap& subset_map, bool isReplace, bool& extendedSomething) {
|
1896
|
+
std::set<SimpleSequence_Selector> seen;
|
1897
|
+
return extendSelectorList(pSelectorList, ctx, subset_map, isReplace, extendedSomething, seen);
|
1898
|
+
}
|
1899
|
+
|
1900
|
+
/*
|
1901
|
+
This is the equivalent of ruby's CommaSequence.do_extend.
|
1902
|
+
*/
|
1903
|
+
CommaSequence_Selector* Extend::extendSelectorList(CommaSequence_Selector* pSelectorList, Context& ctx, ExtensionSubsetMap& subset_map, bool isReplace, bool& extendedSomething, std::set<SimpleSequence_Selector>& seen) {
|
1910
1904
|
|
1911
|
-
|
1905
|
+
CommaSequence_Selector* pNewSelectors = SASS_MEMORY_NEW(ctx.mem, CommaSequence_Selector, pSelectorList->pstate(), pSelectorList->length());
|
1912
1906
|
|
1913
1907
|
extendedSomething = false;
|
1914
1908
|
|
1915
1909
|
for (size_t index = 0, length = pSelectorList->length(); index < length; index++) {
|
1916
|
-
|
1910
|
+
Sequence_Selector* pSelector = (*pSelectorList)[index];
|
1917
1911
|
|
1918
1912
|
// ruby sass seems to keep a list of things that have extensions and then only extend those. We don't currently do that.
|
1919
1913
|
// Since it's not that expensive to check if an extension exists in the subset map and since it can be relatively expensive to
|
1920
1914
|
// run through the extend code (which does a data model transformation), check if there is anything to extend before doing
|
1921
1915
|
// the extend. We might be able to optimize extendComplexSelector, but this approach keeps us closer to ruby sass (which helps
|
1922
1916
|
// when debugging).
|
1923
|
-
if (!complexSelectorHasExtension(pSelector, ctx, subset_map)) {
|
1917
|
+
if (!complexSelectorHasExtension(pSelector, ctx, subset_map, seen)) {
|
1924
1918
|
*pNewSelectors << pSelector;
|
1925
1919
|
continue;
|
1926
1920
|
}
|
1927
1921
|
|
1928
1922
|
extendedSomething = true;
|
1929
1923
|
|
1930
|
-
std::set<Compound_Selector> seen;
|
1931
|
-
|
1932
1924
|
Node extendedSelectors = extendComplexSelector(pSelector, ctx, subset_map, seen, isReplace, true);
|
1933
1925
|
if (!pSelector->has_placeholder()) {
|
1934
1926
|
if (!extendedSelectors.contains(complexSelectorToNode(pSelector, ctx), true /*simpleSelectorOrderDependent*/)) {
|
1935
1927
|
*pNewSelectors << pSelector;
|
1928
|
+
continue;
|
1936
1929
|
}
|
1937
1930
|
}
|
1938
1931
|
|
@@ -1951,32 +1944,46 @@ namespace Sass {
|
|
1951
1944
|
pNewSelectors = remove_placeholders.remove_placeholders(pNewSelectors);
|
1952
1945
|
|
1953
1946
|
// unwrap all wrapped selectors with inner lists
|
1954
|
-
for (
|
1947
|
+
for (Sequence_Selector* cur : *pNewSelectors) {
|
1955
1948
|
// process tails
|
1956
1949
|
while (cur) {
|
1957
1950
|
// process header
|
1958
|
-
if (cur->head()) {
|
1951
|
+
if (cur->head() && seen.find(*cur->head()) == seen.end()) {
|
1952
|
+
std::set<SimpleSequence_Selector> recseen(seen);
|
1953
|
+
recseen.insert(*cur->head());
|
1959
1954
|
// create a copy since we add multiple items if stuff get unwrapped
|
1960
|
-
|
1955
|
+
SimpleSequence_Selector* cpy_head = SASS_MEMORY_NEW(ctx.mem, SimpleSequence_Selector, cur->pstate());
|
1961
1956
|
for (Simple_Selector* hs : *cur->head()) {
|
1962
1957
|
if (Wrapped_Selector* ws = dynamic_cast<Wrapped_Selector*>(hs)) {
|
1963
|
-
if (
|
1958
|
+
if (CommaSequence_Selector* sl = dynamic_cast<CommaSequence_Selector*>(ws->selector())) {
|
1964
1959
|
// special case for ruby ass
|
1965
1960
|
if (sl->empty()) {
|
1966
1961
|
// this seems inconsistent but it is how ruby sass seems to remove parentheses
|
1967
|
-
*cpy_head << SASS_MEMORY_NEW(ctx.mem,
|
1962
|
+
*cpy_head << SASS_MEMORY_NEW(ctx.mem, Element_Selector, hs->pstate(), ws->name());
|
1968
1963
|
}
|
1969
1964
|
// has wrapped selectors
|
1970
1965
|
else {
|
1971
1966
|
// extend the inner list of wrapped selector
|
1972
|
-
|
1967
|
+
CommaSequence_Selector* ext_sl = extendSelectorList(sl, ctx, subset_map, recseen);
|
1973
1968
|
for (size_t i = 0; i < ext_sl->length(); i += 1) {
|
1974
|
-
if (
|
1969
|
+
if (Sequence_Selector* ext_cs = ext_sl->at(i)) {
|
1975
1970
|
// create clones for wrapped selector and the inner list
|
1976
1971
|
Wrapped_Selector* cpy_ws = SASS_MEMORY_NEW(ctx.mem, Wrapped_Selector, *ws);
|
1977
|
-
|
1972
|
+
CommaSequence_Selector* cpy_ws_sl = SASS_MEMORY_NEW(ctx.mem, CommaSequence_Selector, sl->pstate());
|
1978
1973
|
// remove parent selectors from inner selector
|
1979
|
-
if (ext_cs->first()
|
1974
|
+
if (ext_cs->first() && ext_cs->first()->head()->length() > 0) {
|
1975
|
+
Wrapped_Selector* ext_ws = dynamic_cast<Wrapped_Selector*>(ext_cs->first()->head()->first());
|
1976
|
+
if (ext_ws/* && ext_cs->length() == 1*/) {
|
1977
|
+
CommaSequence_Selector* ws_cs = dynamic_cast<CommaSequence_Selector*>(ext_ws->selector());
|
1978
|
+
SimpleSequence_Selector* ws_ss = ws_cs->first()->head();
|
1979
|
+
if (!(
|
1980
|
+
dynamic_cast<Pseudo_Selector*>(ws_ss->first()) ||
|
1981
|
+
dynamic_cast<Element_Selector*>(ws_ss->first()) ||
|
1982
|
+
dynamic_cast<Placeholder_Selector*>(ws_ss->first())
|
1983
|
+
)) continue;
|
1984
|
+
}
|
1985
|
+
*cpy_ws_sl << ext_cs->first();
|
1986
|
+
}
|
1980
1987
|
// assign list to clone
|
1981
1988
|
cpy_ws->selector(cpy_ws_sl);
|
1982
1989
|
// append the clone
|
@@ -2038,7 +2045,7 @@ namespace Sass {
|
|
2038
2045
|
template <typename ObjectType>
|
2039
2046
|
static void extendObjectWithSelectorAndBlock(ObjectType* pObject, Context& ctx, ExtensionSubsetMap& subset_map) {
|
2040
2047
|
|
2041
|
-
DEBUG_PRINTLN(EXTEND_OBJECT, "FOUND SELECTOR: " << static_cast<
|
2048
|
+
DEBUG_PRINTLN(EXTEND_OBJECT, "FOUND SELECTOR: " << static_cast<CommaSequence_Selector*>(pObject->selector())->to_string(ctx.c_options))
|
2042
2049
|
|
2043
2050
|
// Ruby sass seems to filter nodes that don't have any content well before we get here. I'm not sure the repercussions
|
2044
2051
|
// of doing so, so for now, let's just not extend things that won't be output later.
|
@@ -2048,10 +2055,10 @@ namespace Sass {
|
|
2048
2055
|
}
|
2049
2056
|
|
2050
2057
|
bool extendedSomething = false;
|
2051
|
-
|
2058
|
+
CommaSequence_Selector* pNewSelectorList = Extend::extendSelectorList(static_cast<CommaSequence_Selector*>(pObject->selector()), ctx, subset_map, false, extendedSomething);
|
2052
2059
|
|
2053
2060
|
if (extendedSomething && pNewSelectorList) {
|
2054
|
-
DEBUG_PRINTLN(EXTEND_OBJECT, "EXTEND ORIGINAL SELECTORS: " << static_cast<
|
2061
|
+
DEBUG_PRINTLN(EXTEND_OBJECT, "EXTEND ORIGINAL SELECTORS: " << static_cast<CommaSequence_Selector*>(pObject->selector())->to_string(ctx.c_options))
|
2055
2062
|
DEBUG_PRINTLN(EXTEND_OBJECT, "EXTEND SETTING NEW SELECTORS: " << pNewSelectorList->to_string(ctx.c_options))
|
2056
2063
|
pNewSelectorList->remove_parent_selectors();
|
2057
2064
|
pObject->selector(pNewSelectorList);
|
@@ -2076,8 +2083,8 @@ namespace Sass {
|
|
2076
2083
|
if (b->is_root()) {
|
2077
2084
|
// debug_subset_map(subset_map);
|
2078
2085
|
for(auto const &it : subset_map.values()) {
|
2079
|
-
|
2080
|
-
|
2086
|
+
Sequence_Selector* sel = it.first ? it.first->first() : NULL;
|
2087
|
+
SimpleSequence_Selector* ext = it.second ? it.second : NULL;
|
2081
2088
|
if (ext && (ext->extended() || ext->is_optional())) continue;
|
2082
2089
|
std::string str_sel(sel->to_string({ NESTED, 5 }));
|
2083
2090
|
std::string str_ext(ext->to_string({ NESTED, 5 }));
|
@@ -2110,7 +2117,7 @@ namespace Sass {
|
|
2110
2117
|
|
2111
2118
|
void Extend::operator()(Directive* a)
|
2112
2119
|
{
|
2113
|
-
//
|
2120
|
+
// CommaSequence_Selector* ls = dynamic_cast<CommaSequence_Selector*>(a->selector());
|
2114
2121
|
// selector_stack.push_back(ls);
|
2115
2122
|
if (a->block()) a->block()->perform(this);
|
2116
2123
|
// exp.selector_stack.pop_back();
|