sassc 2.2.1 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -0
  3. data/CHANGELOG.md +13 -0
  4. data/Rakefile +1 -3
  5. data/ext/extconf.rb +13 -5
  6. data/ext/libsass/VERSION +1 -1
  7. data/ext/libsass/include/sass/base.h +2 -1
  8. data/ext/libsass/include/sass/context.h +1 -0
  9. data/ext/libsass/src/ast.cpp +49 -59
  10. data/ext/libsass/src/ast.hpp +263 -102
  11. data/ext/libsass/src/ast_def_macros.hpp +8 -0
  12. data/ext/libsass/src/ast_fwd_decl.cpp +2 -1
  13. data/ext/libsass/src/ast_fwd_decl.hpp +40 -116
  14. data/ext/libsass/src/ast_helpers.hpp +292 -0
  15. data/ext/libsass/src/ast_sel_cmp.cpp +209 -722
  16. data/ext/libsass/src/ast_sel_super.cpp +539 -0
  17. data/ext/libsass/src/ast_sel_unify.cpp +207 -212
  18. data/ext/libsass/src/ast_sel_weave.cpp +616 -0
  19. data/ext/libsass/src/ast_selectors.cpp +559 -1001
  20. data/ext/libsass/src/ast_selectors.hpp +311 -367
  21. data/ext/libsass/src/ast_supports.cpp +1 -17
  22. data/ext/libsass/src/ast_values.cpp +216 -29
  23. data/ext/libsass/src/ast_values.hpp +42 -33
  24. data/ext/libsass/src/bind.cpp +1 -1
  25. data/ext/libsass/src/cencode.c +4 -6
  26. data/ext/libsass/src/check_nesting.cpp +5 -6
  27. data/ext/libsass/src/check_nesting.hpp +4 -0
  28. data/ext/libsass/src/color_maps.cpp +11 -10
  29. data/ext/libsass/src/color_maps.hpp +0 -8
  30. data/ext/libsass/src/constants.cpp +5 -0
  31. data/ext/libsass/src/constants.hpp +6 -0
  32. data/ext/libsass/src/context.cpp +30 -60
  33. data/ext/libsass/src/context.hpp +8 -20
  34. data/ext/libsass/src/cssize.cpp +36 -120
  35. data/ext/libsass/src/cssize.hpp +4 -10
  36. data/ext/libsass/src/dart_helpers.hpp +199 -0
  37. data/ext/libsass/src/debugger.hpp +364 -207
  38. data/ext/libsass/src/emitter.cpp +3 -4
  39. data/ext/libsass/src/emitter.hpp +0 -2
  40. data/ext/libsass/src/environment.hpp +5 -0
  41. data/ext/libsass/src/error_handling.cpp +21 -0
  42. data/ext/libsass/src/error_handling.hpp +25 -3
  43. data/ext/libsass/src/eval.cpp +33 -153
  44. data/ext/libsass/src/eval.hpp +11 -13
  45. data/ext/libsass/src/eval_selectors.cpp +75 -0
  46. data/ext/libsass/src/expand.cpp +214 -167
  47. data/ext/libsass/src/expand.hpp +26 -6
  48. data/ext/libsass/src/extender.cpp +1186 -0
  49. data/ext/libsass/src/extender.hpp +399 -0
  50. data/ext/libsass/src/extension.cpp +43 -0
  51. data/ext/libsass/src/extension.hpp +89 -0
  52. data/ext/libsass/src/file.cpp +15 -14
  53. data/ext/libsass/src/file.hpp +5 -12
  54. data/ext/libsass/src/fn_colors.cpp +12 -10
  55. data/ext/libsass/src/fn_lists.cpp +12 -11
  56. data/ext/libsass/src/fn_miscs.cpp +22 -34
  57. data/ext/libsass/src/fn_numbers.cpp +13 -6
  58. data/ext/libsass/src/fn_selectors.cpp +94 -124
  59. data/ext/libsass/src/fn_strings.cpp +16 -14
  60. data/ext/libsass/src/fn_utils.cpp +5 -6
  61. data/ext/libsass/src/fn_utils.hpp +9 -3
  62. data/ext/libsass/src/inspect.cpp +154 -117
  63. data/ext/libsass/src/inspect.hpp +10 -8
  64. data/ext/libsass/src/lexer.cpp +17 -81
  65. data/ext/libsass/src/lexer.hpp +5 -16
  66. data/ext/libsass/src/listize.cpp +22 -36
  67. data/ext/libsass/src/listize.hpp +8 -9
  68. data/ext/libsass/src/memory/SharedPtr.hpp +39 -5
  69. data/ext/libsass/src/operation.hpp +27 -17
  70. data/ext/libsass/src/operators.cpp +1 -0
  71. data/ext/libsass/src/ordered_map.hpp +112 -0
  72. data/ext/libsass/src/output.cpp +30 -49
  73. data/ext/libsass/src/output.hpp +1 -1
  74. data/ext/libsass/src/parser.cpp +211 -381
  75. data/ext/libsass/src/parser.hpp +17 -15
  76. data/ext/libsass/src/parser_selectors.cpp +189 -0
  77. data/ext/libsass/src/permutate.hpp +140 -0
  78. data/ext/libsass/src/position.hpp +1 -1
  79. data/ext/libsass/src/prelexer.cpp +6 -6
  80. data/ext/libsass/src/remove_placeholders.cpp +55 -56
  81. data/ext/libsass/src/remove_placeholders.hpp +21 -18
  82. data/ext/libsass/src/sass.hpp +1 -0
  83. data/ext/libsass/src/sass2scss.cpp +4 -4
  84. data/ext/libsass/src/sass_context.cpp +42 -91
  85. data/ext/libsass/src/sass_context.hpp +2 -2
  86. data/ext/libsass/src/sass_functions.cpp +1 -1
  87. data/ext/libsass/src/sass_values.cpp +0 -1
  88. data/ext/libsass/src/stylesheet.cpp +22 -0
  89. data/ext/libsass/src/stylesheet.hpp +57 -0
  90. data/ext/libsass/src/to_value.cpp +2 -2
  91. data/ext/libsass/src/to_value.hpp +1 -1
  92. data/ext/libsass/src/units.cpp +5 -3
  93. data/ext/libsass/src/util.cpp +10 -12
  94. data/ext/libsass/src/util.hpp +2 -3
  95. data/ext/libsass/src/util_string.cpp +111 -61
  96. data/ext/libsass/src/util_string.hpp +61 -8
  97. data/lib/sassc/engine.rb +5 -3
  98. data/lib/sassc/functions_handler.rb +8 -8
  99. data/lib/sassc/native.rb +1 -1
  100. data/lib/sassc/script.rb +4 -4
  101. data/lib/sassc/version.rb +1 -1
  102. data/test/functions_test.rb +18 -1
  103. data/test/native_test.rb +1 -1
  104. metadata +17 -12
  105. data/ext/libsass/src/extend.cpp +0 -2132
  106. data/ext/libsass/src/extend.hpp +0 -86
  107. data/ext/libsass/src/node.cpp +0 -322
  108. data/ext/libsass/src/node.hpp +0 -118
  109. data/ext/libsass/src/paths.hpp +0 -71
  110. data/ext/libsass/src/sass_util.cpp +0 -152
  111. data/ext/libsass/src/sass_util.hpp +0 -256
  112. data/ext/libsass/src/subset_map.cpp +0 -58
  113. data/ext/libsass/src/subset_map.hpp +0 -76
@@ -0,0 +1,75 @@
1
+ // sass.hpp must go before all system headers to get the
2
+ // __EXTENSIONS__ fix on Solaris.
3
+ #include "sass.hpp"
4
+ #include "expand.hpp"
5
+ #include "eval.hpp"
6
+ #include "ast.hpp"
7
+
8
+
9
+ namespace Sass {
10
+
11
+ SelectorList* Eval::operator()(SelectorList* s)
12
+ {
13
+ std::vector<SelectorListObj> rv;
14
+ SelectorListObj sl = SASS_MEMORY_NEW(SelectorList, s->pstate());
15
+ for (size_t i = 0, iL = s->length(); i < iL; ++i) {
16
+ rv.push_back(operator()(s->get(i)));
17
+ }
18
+
19
+ // we should actually permutate parent first
20
+ // but here we have permutated the selector first
21
+ size_t round = 0;
22
+ while (round != std::string::npos) {
23
+ bool abort = true;
24
+ for (size_t i = 0, iL = rv.size(); i < iL; ++i) {
25
+ if (rv[i]->length() > round) {
26
+ sl->append((*rv[i])[round]);
27
+ abort = false;
28
+ }
29
+ }
30
+ if (abort) {
31
+ round = std::string::npos;
32
+ }
33
+ else {
34
+ ++round;
35
+ }
36
+
37
+ }
38
+ return sl.detach();
39
+ }
40
+
41
+ SelectorComponent* Eval::operator()(SelectorComponent* s)
42
+ {
43
+ return {};
44
+ }
45
+
46
+ SelectorList* Eval::operator()(ComplexSelector* s)
47
+ {
48
+ bool implicit_parent = !exp.old_at_root_without_rule;
49
+ if (is_in_selector_schema) exp.pushNullSelector();
50
+ SelectorListObj other = s->resolve_parent_refs(
51
+ exp.getOriginalStack(), traces, implicit_parent);
52
+ if (is_in_selector_schema) exp.popNullSelector();
53
+
54
+ for (size_t i = 0; i < other->length(); i++) {
55
+ ComplexSelectorObj sel = other->at(i);
56
+ for (size_t n = 0; n < sel->length(); n++) {
57
+ if (CompoundSelectorObj comp = Cast<CompoundSelector>(sel->at(n))) {
58
+ sel->at(n) = operator()(comp);
59
+ }
60
+ }
61
+ }
62
+
63
+ return other.detach();
64
+ }
65
+
66
+ CompoundSelector* Eval::operator()(CompoundSelector* s)
67
+ {
68
+ for (size_t i = 0; i < s->length(); i++) {
69
+ SimpleSelector* ss = s->at(i);
70
+ // skip parents here (called via resolve_parent_refs)
71
+ s->at(i) = Cast<SimpleSelector>(ss->perform(this));
72
+ }
73
+ return s;
74
+ }
75
+ }
@@ -19,7 +19,7 @@ namespace Sass {
19
19
  // simple endless recursion protection
20
20
  const size_t maxRecursion = 500;
21
21
 
22
- Expand::Expand(Context& ctx, Env* env, SelectorStack* stack)
22
+ Expand::Expand(Context& ctx, Env* env, SelectorStack* stack, SelectorStack* originals)
23
23
  : ctx(ctx),
24
24
  traces(ctx.traces),
25
25
  eval(Eval(*this)),
@@ -27,19 +27,32 @@ namespace Sass {
27
27
  in_keyframes(false),
28
28
  at_root_without_rule(false),
29
29
  old_at_root_without_rule(false),
30
- env_stack(EnvStack()),
31
- block_stack(BlockStack()),
32
- call_stack(CallStack()),
33
- selector_stack(SelectorStack()),
34
- media_stack(MediaStack())
30
+ env_stack(),
31
+ block_stack(),
32
+ call_stack(),
33
+ selector_stack(),
34
+ originalStack(),
35
+ mediaStack()
35
36
  {
36
37
  env_stack.push_back(nullptr);
37
38
  env_stack.push_back(env);
38
39
  block_stack.push_back(nullptr);
39
40
  call_stack.push_back({});
40
- if (stack == NULL) { selector_stack.push_back({}); }
41
- else { selector_stack.insert(selector_stack.end(), stack->begin(), stack->end()); }
42
- media_stack.push_back(nullptr);
41
+ if (stack == NULL) { pushToSelectorStack({}); }
42
+ else {
43
+ for (auto item : *stack) {
44
+ if (item.isNull()) pushToSelectorStack({});
45
+ else pushToSelectorStack(item);
46
+ }
47
+ }
48
+ if (originals == NULL) { pushToOriginalStack({}); }
49
+ else {
50
+ for (auto item : *stack) {
51
+ if (item.isNull()) pushToOriginalStack({});
52
+ else pushToOriginalStack(item);
53
+ }
54
+ }
55
+ mediaStack.push_back({});
43
56
  }
44
57
 
45
58
  Env* Expand::environment()
@@ -49,11 +62,80 @@ namespace Sass {
49
62
  return 0;
50
63
  }
51
64
 
52
- Selector_List_Obj Expand::selector()
65
+ void Expand::pushNullSelector()
66
+ {
67
+ pushToSelectorStack({});
68
+ pushToOriginalStack({});
69
+ }
70
+
71
+ void Expand::popNullSelector()
72
+ {
73
+ popFromOriginalStack();
74
+ popFromSelectorStack();
75
+ }
76
+
77
+ SelectorStack Expand::getOriginalStack()
78
+ {
79
+ return originalStack;
80
+ }
81
+
82
+ SelectorStack Expand::getSelectorStack()
53
83
  {
54
- if (selector_stack.size() > 0)
55
- return selector_stack.back();
56
- return {};
84
+ return selector_stack;
85
+ }
86
+
87
+ SelectorListObj& Expand::selector()
88
+ {
89
+ if (selector_stack.size() > 0) {
90
+ auto& sel = selector_stack.back();
91
+ if (sel.isNull()) return sel;
92
+ return sel;
93
+ }
94
+ // Avoid the need to return copies
95
+ // We always want an empty first item
96
+ selector_stack.push_back({});
97
+ return selector_stack.back();;
98
+ }
99
+
100
+ SelectorListObj& Expand::original()
101
+ {
102
+ if (originalStack.size() > 0) {
103
+ auto& sel = originalStack.back();
104
+ if (sel.isNull()) return sel;
105
+ return sel;
106
+ }
107
+ // Avoid the need to return copies
108
+ // We always want an empty first item
109
+ originalStack.push_back({});
110
+ return originalStack.back();
111
+ }
112
+
113
+ SelectorListObj Expand::popFromSelectorStack()
114
+ {
115
+ SelectorListObj last = selector_stack.back();
116
+ if (selector_stack.size() > 0)
117
+ selector_stack.pop_back();
118
+ if (last.isNull()) return {};
119
+ return last;
120
+ }
121
+
122
+ void Expand::pushToSelectorStack(SelectorListObj selector)
123
+ {
124
+ selector_stack.push_back(selector);
125
+ }
126
+
127
+ SelectorListObj Expand::popFromOriginalStack()
128
+ {
129
+ SelectorListObj last = originalStack.back();
130
+ if (originalStack.size() > 0)
131
+ originalStack.pop_back();
132
+ if (last.isNull()) return {};
133
+ return last;
134
+ }
135
+
136
+ void Expand::pushToOriginalStack(SelectorListObj selector)
137
+ {
138
+ originalStack.push_back(selector);
57
139
  }
58
140
 
59
141
  // blocks create new variable scopes
@@ -87,69 +169,55 @@ namespace Sass {
87
169
  if (in_keyframes) {
88
170
  Block* bb = operator()(r->block());
89
171
  Keyframe_Rule_Obj k = SASS_MEMORY_NEW(Keyframe_Rule, r->pstate(), bb);
90
- if (r->selector()) {
91
- if (Selector_List* s = r->selector()) {
92
- selector_stack.push_back({});
93
- k->name(s->eval(eval));
94
- selector_stack.pop_back();
172
+ if (r->schema()) {
173
+ pushNullSelector();
174
+ k->name(eval(r->schema()));
175
+ popNullSelector();
176
+ }
177
+ else if (r->selector()) {
178
+ if (SelectorListObj s = r->selector()) {
179
+ pushNullSelector();
180
+ k->name(eval(s));
181
+ popNullSelector();
95
182
  }
96
183
  }
184
+
97
185
  return k.detach();
98
186
  }
99
187
 
100
- // reset when leaving scope
101
- LOCAL_FLAG(at_root_without_rule, false);
102
-
103
- // `&` is allowed in `@at-root`!
104
- bool has_parent_selector = false;
105
- for (size_t i = 0, L = selector_stack.size(); i < L && !has_parent_selector; i++) {
106
- Selector_List_Obj ll = selector_stack.at(i);
107
- has_parent_selector = ll != nullptr && ll->length() > 0;
108
- }
109
-
110
- Selector_List_Obj sel = r->selector();
111
- if (sel) sel = sel->eval(eval);
112
-
113
- // check for parent selectors in base level rules
114
- if (r->is_root() || (block_stack.back() && block_stack.back()->is_root())) {
115
- if (Selector_List* selector_list = Cast<Selector_List>(r->selector())) {
116
- for (Complex_Selector_Obj complex_selector : selector_list->elements()) {
117
- Complex_Selector* tail = complex_selector;
118
- while (tail) {
119
- if (tail->head()) for (Simple_Selector_Obj header : tail->head()->elements()) {
120
- Parent_Selector* ptr = Cast<Parent_Selector>(header);
121
- if (ptr == NULL || (!ptr->real() || has_parent_selector)) continue;
122
- std::string sel_str(complex_selector->to_string(ctx.c_options));
123
- error("Base-level rules cannot contain the parent-selector-referencing character '&'.", header->pstate(), traces);
124
- }
125
- tail = tail->tail();
126
- }
127
- }
128
- }
129
- }
130
- else {
131
- if (sel->length() == 0 || sel->has_parent_ref()) {
132
- if (sel->has_real_parent_ref() && !has_parent_selector) {
133
- error("Base-level rules cannot contain the parent-selector-referencing character '&'.", sel->pstate(), traces);
134
- }
188
+ if (r->schema()) {
189
+ SelectorListObj sel = eval(r->schema());
190
+ r->selector(sel);
191
+ bool chroot = sel->has_real_parent_ref();
192
+ for (auto complex : sel->elements()) {
193
+ complex->chroots(chroot);
135
194
  }
195
+
136
196
  }
137
197
 
198
+ // reset when leaving scope
199
+ LOCAL_FLAG(at_root_without_rule, false);
200
+
201
+ SelectorListObj evaled = eval(r->selector());
138
202
  // do not connect parent again
139
- sel->remove_parent_selectors();
140
- selector_stack.push_back(sel);
141
203
  Env env(environment());
142
204
  if (block_stack.back()->is_root()) {
143
205
  env_stack.push_back(&env);
144
206
  }
145
- sel->set_media_block(media_stack.back());
146
207
  Block_Obj blk;
208
+ pushToSelectorStack(evaled);
209
+ // The copy is needed for parent reference evaluation
210
+ // dart-sass stores it as `originalSelector` member
211
+ pushToOriginalStack(SASS_MEMORY_COPY(evaled));
212
+ ctx.extender.addSelector(evaled, mediaStack.back());
147
213
  if (r->block()) blk = operator()(r->block());
214
+ popFromOriginalStack();
215
+ popFromSelectorStack();
148
216
  Ruleset* rr = SASS_MEMORY_NEW(Ruleset,
149
217
  r->pstate(),
150
- sel,
218
+ evaled,
151
219
  blk);
152
- selector_stack.pop_back();
220
+
153
221
  if (block_stack.back()->is_root()) {
154
222
  env_stack.pop_back();
155
223
  }
@@ -170,31 +238,44 @@ namespace Sass {
170
238
  return ff.detach();
171
239
  }
172
240
 
173
- Statement* Expand::operator()(Media_Block* m)
241
+ std::vector<CssMediaQuery_Obj> Expand::mergeMediaQueries(
242
+ const std::vector<CssMediaQuery_Obj>& lhs,
243
+ const std::vector<CssMediaQuery_Obj>& rhs)
174
244
  {
175
- Media_Block_Obj cpy = SASS_MEMORY_COPY(m);
176
- // Media_Blocks are prone to have circular references
177
- // Copy could leak memory if it does not get picked up
178
- // Looks like we are able to reset block reference for copy
179
- // Good as it will ensure a low memory overhead for this fix
180
- // So this is a cheap solution with a minimal price
181
- ctx.ast_gc.push_back(cpy); cpy->block({});
182
- Expression_Obj mq = eval(m->media_queries());
183
- std::string str_mq(mq->to_string(ctx.c_options));
245
+ std::vector<CssMediaQuery_Obj> queries;
246
+ for (CssMediaQuery_Obj query1 : lhs) {
247
+ for (CssMediaQuery_Obj query2 : rhs) {
248
+ CssMediaQuery_Obj result = query1->merge(query2);
249
+ if (result && !result->empty()) {
250
+ queries.push_back(result);
251
+ }
252
+ }
253
+ }
254
+ return queries;
255
+ }
256
+
257
+ Statement* Expand::operator()(MediaRule* m)
258
+ {
259
+ Expression_Obj mq = eval(m->schema());
260
+ std::string str_mq(mq->to_css(ctx.c_options));
184
261
  char* str = sass_copy_c_string(str_mq.c_str());
185
262
  ctx.strings.push_back(str);
186
- Parser p(Parser::from_c_str(str, ctx, traces, mq->pstate()));
187
- mq = p.parse_media_queries(); // re-assign now
188
- cpy->media_queries(mq);
189
- media_stack.push_back(cpy);
190
- Block_Obj blk = operator()(m->block());
191
- Media_Block* mm = SASS_MEMORY_NEW(Media_Block,
192
- m->pstate(),
193
- mq,
194
- blk);
195
- media_stack.pop_back();
196
- mm->tabs(m->tabs());
197
- return mm;
263
+ Parser parser(Parser::from_c_str(str, ctx, traces, mq->pstate()));
264
+ // Create a new CSS only representation of the media rule
265
+ CssMediaRuleObj css = SASS_MEMORY_NEW(CssMediaRule, m->pstate(), m->block());
266
+ std::vector<CssMediaQuery_Obj> parsed = parser.parseCssMediaQueries();
267
+ if (mediaStack.size() && mediaStack.back()) {
268
+ auto& parent = mediaStack.back()->elements();
269
+ css->concat(mergeMediaQueries(parent, parsed));
270
+ }
271
+ else {
272
+ css->concat(parsed);
273
+ }
274
+ mediaStack.push_back(css);
275
+ css->block(operator()(m->block()));
276
+ mediaStack.pop_back();
277
+ return css.detach();
278
+
198
279
  }
199
280
 
200
281
  Statement* Expand::operator()(At_Root_Block* a)
@@ -222,12 +303,12 @@ namespace Sass {
222
303
  {
223
304
  LOCAL_FLAG(in_keyframes, a->is_keyframes());
224
305
  Block* ab = a->block();
225
- Selector_List* as = a->selector();
306
+ SelectorList* as = a->selector();
226
307
  Expression* av = a->value();
227
- selector_stack.push_back({});
308
+ pushNullSelector();
228
309
  if (av) av = av->perform(&eval);
229
310
  if (as) as = eval(as);
230
- selector_stack.pop_back();
311
+ popNullSelector();
231
312
  Block* bb = ab ? operator()(ab) : NULL;
232
313
  Directive* aa = SASS_MEMORY_NEW(Directive,
233
314
  a->pstate(),
@@ -497,9 +578,8 @@ namespace Sass {
497
578
  if (expr->concrete_type() == Expression::MAP) {
498
579
  map = Cast<Map>(expr);
499
580
  }
500
- else if (Selector_List* ls = Cast<Selector_List>(expr)) {
501
- Listize listize;
502
- Expression_Obj rv = ls->perform(&listize);
581
+ else if (SelectorList * ls = Cast<SelectorList>(expr)) {
582
+ Expression_Obj rv = Listize::perform(ls);
503
583
  list = Cast<List>(rv);
504
584
  }
505
585
  else if (expr->concrete_type() != Expression::LIST) {
@@ -534,7 +614,7 @@ namespace Sass {
534
614
  }
535
615
  else {
536
616
  // bool arglist = list->is_arglist();
537
- if (list->length() == 1 && Cast<Selector_List>(list)) {
617
+ if (list->length() == 1 && Cast<SelectorList>(list)) {
538
618
  list = Cast<List>(list);
539
619
  }
540
620
  for (size_t i = 0, L = list->length(); i < L; ++i) {
@@ -595,87 +675,63 @@ namespace Sass {
595
675
  return 0;
596
676
  }
597
677
 
678
+ Statement* Expand::operator()(ExtendRule* e)
679
+ {
598
680
 
599
- void Expand::expand_selector_list(Selector_Obj s, Selector_List_Obj extender) {
600
-
601
- if (Selector_List_Obj sl = Cast<Selector_List>(s)) {
602
- for (Complex_Selector_Obj complex_selector : sl->elements()) {
603
- Complex_Selector_Obj tail = complex_selector;
604
- while (tail) {
605
- if (tail->head()) for (Simple_Selector_Obj header : tail->head()->elements()) {
606
- if (Cast<Parent_Selector>(header) == NULL) continue; // skip all others
607
- std::string sel_str(complex_selector->to_string(ctx.c_options));
608
- error("Can't extend " + sel_str + ": can't extend parent selectors", header->pstate(), traces);
609
- }
610
- tail = tail->tail();
611
- }
612
- }
681
+ // evaluate schema first
682
+ if (e->schema()) {
683
+ e->selector(eval(e->schema()));
684
+ e->isOptional(e->selector()->is_optional());
613
685
  }
686
+ // evaluate the selector
687
+ e->selector(eval(e->selector()));
614
688
 
689
+ if (e->selector()) {
615
690
 
616
- Selector_List_Obj contextualized = Cast<Selector_List>(s->perform(&eval));
617
- if (contextualized == nullptr) return;
618
- for (auto complex_sel : contextualized->elements()) {
619
- Complex_Selector_Obj c = complex_sel;
620
- if (!c->head() || c->tail()) {
621
- std::string sel_str(contextualized->to_string(ctx.c_options));
622
- error("Can't extend " + sel_str + ": can't extend nested selectors", c->pstate(), traces);
623
- }
624
- Compound_Selector_Obj target = c->head();
625
- if (contextualized->is_optional()) target->is_optional(true);
626
- for (size_t i = 0, L = extender->length(); i < L; ++i) {
627
- Complex_Selector_Obj sel = (*extender)[i];
628
- if (!(sel->head() && sel->head()->length() > 0 &&
629
- Cast<Parent_Selector>((*sel->head())[0])))
630
- {
631
- Compound_Selector_Obj hh = SASS_MEMORY_NEW(Compound_Selector, (*extender)[i]->pstate());
632
- hh->media_block((*extender)[i]->media_block());
633
- Complex_Selector_Obj ssel = SASS_MEMORY_NEW(Complex_Selector, (*extender)[i]->pstate());
634
- ssel->media_block((*extender)[i]->media_block());
635
- if (sel->has_line_feed()) ssel->has_line_feed(true);
636
- Parent_Selector_Obj ps = SASS_MEMORY_NEW(Parent_Selector, (*extender)[i]->pstate());
637
- ps->media_block((*extender)[i]->media_block());
638
- hh->append(ps);
639
- ssel->tail(sel);
640
- ssel->head(hh);
641
- sel = ssel;
691
+ for (auto complex : e->selector()->elements()) {
692
+
693
+ if (complex->length() != 1) {
694
+ error("complex selectors may not be extended.", complex->pstate(), traces);
642
695
  }
643
- // if (c->has_line_feed()) sel->has_line_feed(true);
644
- ctx.subset_map.put(target, std::make_pair(sel, target));
645
- }
646
- }
647
696
 
648
- }
697
+ if (const CompoundSelector* compound = complex->first()->getCompound()) {
698
+
699
+ if (compound->length() != 1) {
700
+
701
+ std::stringstream sels; bool addComma = false;
702
+ sels << "Compound selectors may no longer be extended.\n";
703
+ sels << "Consider `@extend ";
704
+ for (auto sel : compound->elements()) {
705
+ if (addComma) sels << ", ";
706
+ sels << sel->to_sass();
707
+ addComma = true;
708
+ }
709
+ sels << "` instead.\n";
710
+ sels << "See http://bit.ly/ExtendCompound for details.";
711
+
712
+ warning(sels.str(), compound->pstate());
713
+
714
+ // Make this an error once deprecation is over
715
+ for (SimpleSelectorObj simple : compound->elements()) {
716
+ // Pass every selector we ever see to extender (to make them findable for extend)
717
+ ctx.extender.addExtension(selector(), simple, mediaStack.back(), e->isOptional());
718
+ }
719
+
720
+ }
721
+ else {
722
+ // Pass every selector we ever see to extender (to make them findable for extend)
723
+ ctx.extender.addExtension(selector(), compound->first(), mediaStack.back(), e->isOptional());
724
+ }
649
725
 
650
- Statement* Expand::operator()(Extension* e)
651
- {
652
- if (Selector_List_Obj extender = selector()) {
653
- Selector_List* sl = e->selector();
654
- // abort on invalid selector
655
- if (sl == NULL) return NULL;
656
- if (Selector_Schema* schema = sl->schema()) {
657
- if (schema->has_real_parent_ref()) {
658
- // put root block on stack again (ignore parents)
659
- // selector schema must not connect in eval!
660
- block_stack.push_back(block_stack.at(1));
661
- sl = eval(sl->schema());
662
- block_stack.pop_back();
663
- } else {
664
- selector_stack.push_back({});
665
- sl = eval(sl->schema());
666
- selector_stack.pop_back();
667
726
  }
668
- }
669
- for (Complex_Selector_Obj cs : sl->elements()) {
670
- if (!cs.isNull() && !cs->head().isNull()) {
671
- cs->head()->media_block(media_stack.back());
727
+ else {
728
+ error("complex selectors may not be extended.", complex->pstate(), traces);
672
729
  }
673
730
  }
674
- selector_stack.push_back({});
675
- expand_selector_list(sl, extender);
676
- selector_stack.pop_back();
677
731
  }
678
- return 0;
732
+
733
+ return nullptr;
734
+
679
735
  }
680
736
 
681
737
  Statement* Expand::operator()(Definition* d)
@@ -705,6 +761,7 @@ namespace Sass {
705
761
 
706
762
  Statement* Expand::operator()(Mixin_Call* c)
707
763
  {
764
+
708
765
  if (recursions > maxRecursion) {
709
766
  throw Exception::StackError(traces, *c);
710
767
  }
@@ -785,11 +842,6 @@ namespace Sass {
785
842
  Env* env = environment();
786
843
  // convert @content directives into mixin calls to the underlying thunk
787
844
  if (!env->has("@content[m]")) return 0;
788
-
789
- if (block_stack.back()->is_root()) {
790
- selector_stack.push_back({});
791
- }
792
-
793
845
  Arguments_Obj args = c->arguments();
794
846
  if (!args) args = SASS_MEMORY_NEW(Arguments, c->pstate());
795
847
 
@@ -799,11 +851,6 @@ namespace Sass {
799
851
  args);
800
852
 
801
853
  Trace_Obj trace = Cast<Trace>(call->perform(this));
802
-
803
- if (block_stack.back()->is_root()) {
804
- selector_stack.pop_back();
805
- }
806
-
807
854
  return trace.detach();
808
855
  }
809
856