8 #include "backtrace.hpp"
12 Cssize::Cssize(Context& ctx, Backtrace* bt)
14 block_stack(std::vector<Block_Ptr>()),
15 p_stack(std::vector<Statement_Ptr>()),
19 Statement_Ptr Cssize::parent()
21 return p_stack.size() ? p_stack.back() : block_stack.front();
24 Block_Ptr Cssize::operator()(Block_Ptr b)
26 Block_Ptr bb = SASS_MEMORY_NEW(Block, b->pstate(), b->length(), b->is_root());
27 // bb->tabs(b->tabs());
28 block_stack.push_back(bb);
30 block_stack.pop_back();
34 Statement_Ptr Cssize::operator()(Trace_Ptr t)
36 return t->block()->perform(this);
39 Statement_Ptr Cssize::operator()(Declaration_Ptr d)
41 String_Obj property = Cast<String>(d->property());
43 if (Declaration_Ptr dd = Cast<Declaration>(parent())) {
44 String_Obj parent_property = Cast<String>(dd->property());
45 property = SASS_MEMORY_NEW(String_Constant,
46 d->property()->pstate(),
47 parent_property->to_string() + "-" + property->to_string());
49 d->tabs(dd->tabs() + 1);
53 Declaration_Obj dd = SASS_MEMORY_NEW(Declaration,
58 dd->is_indented(d->is_indented());
61 p_stack.push_back(dd);
62 Block_Obj bb = d->block() ? operator()(d->block()) : NULL;
65 if (bb && bb->length()) {
66 if (dd->value() && !dd->value()->is_invisible()) {
71 else if (dd->value() && !dd->value()->is_invisible()) {
78 Statement_Ptr Cssize::operator()(Directive_Ptr r)
80 if (!r->block() || !r->block()->length()) return r;
82 if (parent()->statement_type() == Statement::RULESET)
84 return (r->is_keyframes()) ? SASS_MEMORY_NEW(Bubble, r->pstate(), r) : bubble(r);
88 Directive_Obj rr = SASS_MEMORY_NEW(Directive,
92 r->block() ? operator()(r->block()) : 0);
93 if (r->value()) rr->value(r->value());
96 bool directive_exists = false;
97 size_t L = rr->block() ? rr->block()->length() : 0;
98 for (size_t i = 0; i < L && !directive_exists; ++i) {
99 Statement_Obj s = r->block()->at(i);
100 if (s->statement_type() != Statement::BUBBLE) directive_exists = true;
102 Bubble_Obj s_obj = Cast<Bubble>(s);
104 if (s->statement_type() != Statement::DIRECTIVE) directive_exists = false;
105 else directive_exists = (Cast<Directive>(s)->keyword() == rr->keyword());
110 Block_Ptr result = SASS_MEMORY_NEW(Block, rr->pstate());
111 if (!(directive_exists || rr->is_keyframes()))
113 Directive_Ptr empty_node = Cast<Directive>(rr);
114 empty_node->block(SASS_MEMORY_NEW(Block, rr->block() ? rr->block()->pstate() : rr->pstate()));
115 result->append(empty_node);
118 Block_Obj db = rr->block();
119 if (db.isNull()) db = SASS_MEMORY_NEW(Block, rr->pstate());
120 Block_Obj ss = debubble(db, rr);
121 for (size_t i = 0, L = ss->length(); i < L; ++i) {
122 result->append(ss->at(i));
128 Statement_Ptr Cssize::operator()(Keyframe_Rule_Ptr r)
130 if (!r->block() || !r->block()->length()) return r;
132 Keyframe_Rule_Obj rr = SASS_MEMORY_NEW(Keyframe_Rule,
134 operator()(r->block()));
135 if (!r->name().isNull()) rr->name(r->name());
137 return debubble(rr->block(), rr);
140 Statement_Ptr Cssize::operator()(Ruleset_Ptr r)
142 p_stack.push_back(r);
143 // this can return a string schema
144 // string schema is not a statement!
145 // r->block() is already a string schema
146 // and that is comming from propset expand
147 Block_Ptr bb = operator()(r->block());
148 // this should protect us (at least a bit) from our mess
149 // fixing this properly is harder that it should be ...
150 if (Cast<Statement>(bb) == NULL) {
151 error("Illegal nesting: Only properties may be nested beneath properties.", r->block()->pstate());
153 Ruleset_Obj rr = SASS_MEMORY_NEW(Ruleset,
158 rr->is_root(r->is_root());
159 // rr->tabs(r->block()->tabs());
163 error("Illegal nesting: Only properties may be nested beneath properties.", r->block()->pstate());
166 Block_Obj props = SASS_MEMORY_NEW(Block, rr->block()->pstate());
167 Block_Ptr rules = SASS_MEMORY_NEW(Block, rr->block()->pstate());
168 for (size_t i = 0, L = rr->block()->length(); i < L; i++)
170 Statement_Ptr s = rr->block()->at(i);
171 if (bubblable(s)) rules->append(s);
172 if (!bubblable(s)) props->append(s);
177 Block_Obj bb = SASS_MEMORY_NEW(Block, rr->block()->pstate());
181 for (size_t i = 0, L = rules->length(); i < L; i++)
183 Statement_Ptr stm = rules->at(i);
184 stm->tabs(stm->tabs() + 1);
190 Block_Ptr ptr = rules;
191 rules = debubble(rules);
198 if (!(!rules->length() ||
199 !bubblable(rules->last()) ||
200 parent()->statement_type() == Statement::RULESET))
202 rules->last()->group_end(true);
207 Statement_Ptr Cssize::operator()(Null_Ptr m)
212 Statement_Ptr Cssize::operator()(Media_Block_Ptr m)
214 if (parent()->statement_type() == Statement::RULESET)
215 { return bubble(m); }
217 if (parent()->statement_type() == Statement::MEDIA)
218 { return SASS_MEMORY_NEW(Bubble, m->pstate(), m); }
220 p_stack.push_back(m);
222 Media_Block_Obj mm = SASS_MEMORY_NEW(Media_Block,
225 operator()(m->block()));
230 return debubble(mm->block(), mm);
233 Statement_Ptr Cssize::operator()(Supports_Block_Ptr m)
235 if (!m->block()->length())
238 if (parent()->statement_type() == Statement::RULESET)
239 { return bubble(m); }
241 p_stack.push_back(m);
243 Supports_Block_Obj mm = SASS_MEMORY_NEW(Supports_Block,
246 operator()(m->block()));
251 return debubble(mm->block(), mm);
254 Statement_Ptr Cssize::operator()(At_Root_Block_Ptr m)
257 for (size_t i = 0, L = p_stack.size(); i < L; ++i) {
258 Statement_Ptr s = p_stack[i];
259 tmp |= m->exclude_node(s);
264 Block_Ptr bb = operator()(m->block());
265 for (size_t i = 0, L = bb->length(); i < L; ++i) {
266 // (bb->elements())[i]->tabs(m->tabs());
267 Statement_Obj stm = bb->at(i);
268 if (bubblable(stm)) stm->tabs(stm->tabs() + m->tabs());
270 if (bb->length() && bubblable(bb->last())) bb->last()->group_end(m->group_end());
274 if (m->exclude_node(parent()))
276 return SASS_MEMORY_NEW(Bubble, m->pstate(), m);
282 Statement_Ptr Cssize::bubble(Directive_Ptr m)
284 Block_Ptr bb = SASS_MEMORY_NEW(Block, this->parent()->pstate());
285 Has_Block_Obj new_rule = Cast<Has_Block>(SASS_MEMORY_COPY(this->parent()));
287 new_rule->tabs(this->parent()->tabs());
288 new_rule->block()->concat(m->block());
290 Block_Obj wrapper_block = SASS_MEMORY_NEW(Block, m->block() ? m->block()->pstate() : m->pstate());
291 wrapper_block->append(new_rule);
292 Directive_Obj mm = SASS_MEMORY_NEW(Directive,
297 if (m->value()) mm->value(m->value());
299 Bubble_Ptr bubble = SASS_MEMORY_NEW(Bubble, mm->pstate(), mm);
303 Statement_Ptr Cssize::bubble(At_Root_Block_Ptr m)
305 Block_Ptr bb = SASS_MEMORY_NEW(Block, this->parent()->pstate());
306 Has_Block_Obj new_rule = Cast<Has_Block>(SASS_MEMORY_COPY(this->parent()));
308 new_rule->tabs(this->parent()->tabs());
309 new_rule->block()->concat(m->block());
311 Block_Ptr wrapper_block = SASS_MEMORY_NEW(Block, m->block()->pstate());
312 wrapper_block->append(new_rule);
313 At_Root_Block_Ptr mm = SASS_MEMORY_NEW(At_Root_Block,
317 Bubble_Ptr bubble = SASS_MEMORY_NEW(Bubble, mm->pstate(), mm);
321 Statement_Ptr Cssize::bubble(Supports_Block_Ptr m)
323 Ruleset_Obj parent = Cast<Ruleset>(SASS_MEMORY_COPY(this->parent()));
325 Block_Ptr bb = SASS_MEMORY_NEW(Block, parent->block()->pstate());
326 Ruleset_Ptr new_rule = SASS_MEMORY_NEW(Ruleset,
330 new_rule->tabs(parent->tabs());
331 new_rule->block()->concat(m->block());
333 Block_Ptr wrapper_block = SASS_MEMORY_NEW(Block, m->block()->pstate());
334 wrapper_block->append(new_rule);
335 Supports_Block_Ptr mm = SASS_MEMORY_NEW(Supports_Block,
342 Bubble_Ptr bubble = SASS_MEMORY_NEW(Bubble, mm->pstate(), mm);
346 Statement_Ptr Cssize::bubble(Media_Block_Ptr m)
348 Ruleset_Obj parent = Cast<Ruleset>(SASS_MEMORY_COPY(this->parent()));
350 Block_Ptr bb = SASS_MEMORY_NEW(Block, parent->block()->pstate());
351 Ruleset_Ptr new_rule = SASS_MEMORY_NEW(Ruleset,
355 new_rule->tabs(parent->tabs());
356 new_rule->block()->concat(m->block());
358 Block_Ptr wrapper_block = SASS_MEMORY_NEW(Block, m->block()->pstate());
359 wrapper_block->append(new_rule);
360 Media_Block_Obj mm = SASS_MEMORY_NEW(Media_Block,
367 return SASS_MEMORY_NEW(Bubble, mm->pstate(), mm);
370 bool Cssize::bubblable(Statement_Ptr s)
372 return Cast<Ruleset>(s) || s->bubbles();
375 Block_Ptr Cssize::flatten(Block_Ptr b)
377 Block_Ptr result = SASS_MEMORY_NEW(Block, b->pstate(), 0, b->is_root());
378 for (size_t i = 0, L = b->length(); i < L; ++i) {
379 Statement_Ptr ss = b->at(i);
380 if (Block_Ptr bb = Cast<Block>(ss)) {
381 Block_Obj bs = flatten(bb);
382 for (size_t j = 0, K = bs->length(); j < K; ++j) {
383 result->append(bs->at(j));
393 std::vector<std::pair<bool, Block_Obj>> Cssize::slice_by_bubble(Block_Ptr b)
395 std::vector<std::pair<bool, Block_Obj>> results;
397 for (size_t i = 0, L = b->length(); i < L; ++i) {
398 Statement_Obj value = b->at(i);
399 bool key = Cast<Bubble>(value) != NULL;
401 if (!results.empty() && results.back().first == key)
403 Block_Obj wrapper_block = results.back().second;
404 wrapper_block->append(value);
408 Block_Ptr wrapper_block = SASS_MEMORY_NEW(Block, value->pstate());
409 wrapper_block->append(value);
410 results.push_back(std::make_pair(key, wrapper_block));
416 Block_Ptr Cssize::debubble(Block_Ptr children, Statement_Ptr parent)
418 Has_Block_Obj previous_parent = 0;
419 std::vector<std::pair<bool, Block_Obj>> baz = slice_by_bubble(children);
420 Block_Obj result = SASS_MEMORY_NEW(Block, children->pstate());
422 for (size_t i = 0, L = baz.size(); i < L; ++i) {
423 bool is_bubble = baz[i].first;
424 Block_Obj slice = baz[i].second;
428 result->append(slice);
430 else if (previous_parent) {
431 previous_parent->block()->concat(slice);
434 previous_parent = Cast<Has_Block>(SASS_MEMORY_COPY(parent));
435 previous_parent->block(slice);
436 previous_parent->tabs(parent->tabs());
438 result->append(previous_parent);
443 for (size_t j = 0, K = slice->length(); j < K; ++j)
445 Statement_Ptr ss = NULL;
446 Statement_Obj stm = slice->at(j);
447 // this has to go now here (too bad)
448 Bubble_Obj node = Cast<Bubble>(stm);
449 Media_Block_Ptr m1 = NULL;
450 Media_Block_Ptr m2 = NULL;
451 if (parent) m1 = Cast<Media_Block>(parent);
452 if (node) m2 = Cast<Media_Block>(node->node());
454 parent->statement_type() != Statement::MEDIA ||
455 node->node()->statement_type() != Statement::MEDIA ||
456 (m1 && m2 && *m1->media_queries() == *m2->media_queries())
463 List_Obj mq = merge_media_queries(
464 Cast<Media_Block>(node->node()),
465 Cast<Media_Block>(parent)
467 if (!mq->length()) continue;
468 if (Media_Block* b = Cast<Media_Block>(node->node())) {
469 b->media_queries(mq);
476 ss->tabs(ss->tabs() + node->tabs());
477 ss->group_end(node->group_end());
481 Block_Obj bb = SASS_MEMORY_NEW(Block,
484 children->is_root());
485 bb->append(ss->perform(this));
487 Block_Obj wrapper_block = SASS_MEMORY_NEW(Block,
490 children->is_root());
492 Block_Ptr wrapper = flatten(bb);
493 wrapper_block->append(wrapper);
495 if (wrapper->length()) {
496 previous_parent = NULL;
500 result->append(wrapper_block);
505 return flatten(result);
508 Statement_Ptr Cssize::fallback_impl(AST_Node_Ptr n)
510 return static_cast<Statement_Ptr>(n);
513 void Cssize::append_block(Block_Ptr b, Block_Ptr cur)
515 for (size_t i = 0, L = b->length(); i < L; ++i) {
516 Statement_Obj ith = b->at(i)->perform(this);
517 if (Block_Ptr bb = Cast<Block>(ith)) {
518 for (size_t j = 0, K = bb->length(); j < K; ++j) {
519 cur->append(bb->at(j));
528 List_Ptr Cssize::merge_media_queries(Media_Block_Ptr m1, Media_Block_Ptr m2)
530 List_Ptr qq = SASS_MEMORY_NEW(List,
531 m1->media_queries()->pstate(),
532 m1->media_queries()->length(),
535 for (size_t i = 0, L = m1->media_queries()->length(); i < L; i++) {
536 for (size_t j = 0, K = m2->media_queries()->length(); j < K; j++) {
537 Expression_Obj l1 = m1->media_queries()->at(i);
538 Expression_Obj l2 = m2->media_queries()->at(j);
539 Media_Query_Ptr mq1 = Cast<Media_Query>(l1);
540 Media_Query_Ptr mq2 = Cast<Media_Query>(l2);
541 Media_Query_Ptr mq = merge_media_query(mq1, mq2);
542 if (mq) qq->append(mq);
550 Media_Query_Ptr Cssize::merge_media_query(Media_Query_Ptr mq1, Media_Query_Ptr mq2)
556 std::string m1 = std::string(mq1->is_restricted() ? "only" : mq1->is_negated() ? "not" : "");
557 std::string t1 = mq1->media_type() ? mq1->media_type()->to_string(ctx.c_options) : "";
558 std::string m2 = std::string(mq2->is_restricted() ? "only" : mq1->is_negated() ? "not" : "");
559 std::string t2 = mq2->media_type() ? mq2->media_type()->to_string(ctx.c_options) : "";
562 if (t1.empty()) t1 = t2;
563 if (t2.empty()) t2 = t1;
565 if ((m1 == "not") ^ (m2 == "not")) {
569 type = m1 == "not" ? t2 : t1;
570 mod = m1 == "not" ? m2 : m1;
572 else if (m1 == "not" && m2 == "not") {
583 mod = m1.empty() ? m2 : m1;
586 Media_Query_Ptr mm = SASS_MEMORY_NEW(Media_Query,
589 mq1->length() + mq2->length(), mod == "not", mod == "only"
593 mm->media_type(SASS_MEMORY_NEW(String_Quoted, mq1->pstate(), type));