Initial commit
[yaffs-website] / node_modules / node-sass / src / libsass / src / cssize.cpp
1 #include "sass.hpp"
2 #include <iostream>
3 #include <typeinfo>
4 #include <vector>
5
6 #include "cssize.hpp"
7 #include "context.hpp"
8 #include "backtrace.hpp"
9
10 namespace Sass {
11
12   Cssize::Cssize(Context& ctx, Backtrace* bt)
13   : ctx(ctx),
14     block_stack(std::vector<Block_Ptr>()),
15     p_stack(std::vector<Statement_Ptr>()),
16     backtrace(bt)
17   { }
18
19   Statement_Ptr Cssize::parent()
20   {
21     return p_stack.size() ? p_stack.back() : block_stack.front();
22   }
23
24   Block_Ptr Cssize::operator()(Block_Ptr b)
25   {
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);
29     append_block(b, bb);
30     block_stack.pop_back();
31     return bb;
32   }
33
34   Statement_Ptr Cssize::operator()(Trace_Ptr t)
35   {
36     return t->block()->perform(this);
37   }
38
39   Statement_Ptr Cssize::operator()(Declaration_Ptr d)
40   {
41     String_Obj property = Cast<String>(d->property());
42
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());
48       if (!dd->value()) {
49         d->tabs(dd->tabs() + 1);
50       }
51     }
52
53     Declaration_Obj dd = SASS_MEMORY_NEW(Declaration,
54                                       d->pstate(),
55                                       property,
56                                       d->value(),
57                                       d->is_important());
58     dd->is_indented(d->is_indented());
59     dd->tabs(d->tabs());
60
61     p_stack.push_back(dd);
62     Block_Obj bb = d->block() ? operator()(d->block()) : NULL;
63     p_stack.pop_back();
64
65     if (bb && bb->length()) {
66       if (dd->value() && !dd->value()->is_invisible()) {
67         bb->unshift(dd);
68       }
69       return bb.detach();
70     }
71     else if (dd->value() && !dd->value()->is_invisible()) {
72       return dd.detach();
73     }
74
75     return 0;
76   }
77
78   Statement_Ptr Cssize::operator()(Directive_Ptr r)
79   {
80     if (!r->block() || !r->block()->length()) return r;
81
82     if (parent()->statement_type() == Statement::RULESET)
83     {
84       return (r->is_keyframes()) ? SASS_MEMORY_NEW(Bubble, r->pstate(), r) : bubble(r);
85     }
86
87     p_stack.push_back(r);
88     Directive_Obj rr = SASS_MEMORY_NEW(Directive,
89                                   r->pstate(),
90                                   r->keyword(),
91                                   r->selector(),
92                                   r->block() ? operator()(r->block()) : 0);
93     if (r->value()) rr->value(r->value());
94     p_stack.pop_back();
95
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;
101       else {
102         Bubble_Obj s_obj = Cast<Bubble>(s);
103         s = s_obj->node();
104         if (s->statement_type() != Statement::DIRECTIVE) directive_exists = false;
105         else directive_exists = (Cast<Directive>(s)->keyword() == rr->keyword());
106       }
107
108     }
109
110     Block_Ptr result = SASS_MEMORY_NEW(Block, rr->pstate());
111     if (!(directive_exists || rr->is_keyframes()))
112     {
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);
116     }
117
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));
123     }
124
125     return result;
126   }
127
128   Statement_Ptr Cssize::operator()(Keyframe_Rule_Ptr r)
129   {
130     if (!r->block() || !r->block()->length()) return r;
131
132     Keyframe_Rule_Obj rr = SASS_MEMORY_NEW(Keyframe_Rule,
133                                         r->pstate(),
134                                         operator()(r->block()));
135     if (!r->name().isNull()) rr->name(r->name());
136
137     return debubble(rr->block(), rr);
138   }
139
140   Statement_Ptr Cssize::operator()(Ruleset_Ptr r)
141   {
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());
152     }
153     Ruleset_Obj rr = SASS_MEMORY_NEW(Ruleset,
154                                   r->pstate(),
155                                   r->selector(),
156                                   bb);
157
158     rr->is_root(r->is_root());
159     // rr->tabs(r->block()->tabs());
160     p_stack.pop_back();
161
162     if (!rr->block()) {
163       error("Illegal nesting: Only properties may be nested beneath properties.", r->block()->pstate());
164     }
165
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++)
169     {
170       Statement_Ptr s = rr->block()->at(i);
171       if (bubblable(s)) rules->append(s);
172       if (!bubblable(s)) props->append(s);
173     }
174
175     if (props->length())
176     {
177       Block_Obj bb = SASS_MEMORY_NEW(Block, rr->block()->pstate());
178       bb->concat(props);
179       rr->block(bb);
180
181       for (size_t i = 0, L = rules->length(); i < L; i++)
182       {
183         Statement_Ptr stm = rules->at(i);
184         stm->tabs(stm->tabs() + 1);
185       }
186
187       rules->unshift(rr);
188     }
189
190     Block_Ptr ptr = rules;
191     rules = debubble(rules);
192     void* lp = ptr;
193     void* rp = rules;
194     if (lp != rp) {
195       Block_Obj obj = ptr;
196     }
197
198     if (!(!rules->length() ||
199           !bubblable(rules->last()) ||
200           parent()->statement_type() == Statement::RULESET))
201     {
202       rules->last()->group_end(true);
203     }
204     return rules;
205   }
206
207   Statement_Ptr Cssize::operator()(Null_Ptr m)
208   {
209     return 0;
210   }
211
212   Statement_Ptr Cssize::operator()(Media_Block_Ptr m)
213   {
214     if (parent()->statement_type() == Statement::RULESET)
215     { return bubble(m); }
216
217     if (parent()->statement_type() == Statement::MEDIA)
218     { return SASS_MEMORY_NEW(Bubble, m->pstate(), m); }
219
220     p_stack.push_back(m);
221
222     Media_Block_Obj mm = SASS_MEMORY_NEW(Media_Block,
223                                       m->pstate(),
224                                       m->media_queries(),
225                                       operator()(m->block()));
226     mm->tabs(m->tabs());
227
228     p_stack.pop_back();
229
230     return debubble(mm->block(), mm);
231   }
232
233   Statement_Ptr Cssize::operator()(Supports_Block_Ptr m)
234   {
235     if (!m->block()->length())
236     { return m; }
237
238     if (parent()->statement_type() == Statement::RULESET)
239     { return bubble(m); }
240
241     p_stack.push_back(m);
242
243     Supports_Block_Obj mm = SASS_MEMORY_NEW(Supports_Block,
244                                        m->pstate(),
245                                        m->condition(),
246                                        operator()(m->block()));
247     mm->tabs(m->tabs());
248
249     p_stack.pop_back();
250
251     return debubble(mm->block(), mm);
252   }
253
254   Statement_Ptr Cssize::operator()(At_Root_Block_Ptr m)
255   {
256     bool tmp = false;
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);
260     }
261
262     if (!tmp)
263     {
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());
269       }
270       if (bb->length() && bubblable(bb->last())) bb->last()->group_end(m->group_end());
271       return bb;
272     }
273
274     if (m->exclude_node(parent()))
275     {
276       return SASS_MEMORY_NEW(Bubble, m->pstate(), m);
277     }
278
279     return bubble(m);
280   }
281
282   Statement_Ptr Cssize::bubble(Directive_Ptr m)
283   {
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()));
286     new_rule->block(bb);
287     new_rule->tabs(this->parent()->tabs());
288     new_rule->block()->concat(m->block());
289
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,
293                                   m->pstate(),
294                                   m->keyword(),
295                                   m->selector(),
296                                   wrapper_block);
297     if (m->value()) mm->value(m->value());
298
299     Bubble_Ptr bubble = SASS_MEMORY_NEW(Bubble, mm->pstate(), mm);
300     return bubble;
301   }
302
303   Statement_Ptr Cssize::bubble(At_Root_Block_Ptr m)
304   {
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()));
307     new_rule->block(bb);
308     new_rule->tabs(this->parent()->tabs());
309     new_rule->block()->concat(m->block());
310
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,
314                                         m->pstate(),
315                                         wrapper_block,
316                                         m->expression());
317     Bubble_Ptr bubble = SASS_MEMORY_NEW(Bubble, mm->pstate(), mm);
318     return bubble;
319   }
320
321   Statement_Ptr Cssize::bubble(Supports_Block_Ptr m)
322   {
323     Ruleset_Obj parent = Cast<Ruleset>(SASS_MEMORY_COPY(this->parent()));
324
325     Block_Ptr bb = SASS_MEMORY_NEW(Block, parent->block()->pstate());
326     Ruleset_Ptr new_rule = SASS_MEMORY_NEW(Ruleset,
327                                         parent->pstate(),
328                                         parent->selector(),
329                                         bb);
330     new_rule->tabs(parent->tabs());
331     new_rule->block()->concat(m->block());
332
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,
336                                        m->pstate(),
337                                        m->condition(),
338                                        wrapper_block);
339
340     mm->tabs(m->tabs());
341
342     Bubble_Ptr bubble = SASS_MEMORY_NEW(Bubble, mm->pstate(), mm);
343     return bubble;
344   }
345
346   Statement_Ptr Cssize::bubble(Media_Block_Ptr m)
347   {
348     Ruleset_Obj parent = Cast<Ruleset>(SASS_MEMORY_COPY(this->parent()));
349
350     Block_Ptr bb = SASS_MEMORY_NEW(Block, parent->block()->pstate());
351     Ruleset_Ptr new_rule = SASS_MEMORY_NEW(Ruleset,
352                                         parent->pstate(),
353                                         parent->selector(),
354                                         bb);
355     new_rule->tabs(parent->tabs());
356     new_rule->block()->concat(m->block());
357
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,
361                                       m->pstate(),
362                                       m->media_queries(),
363                                       wrapper_block);
364
365     mm->tabs(m->tabs());
366
367     return SASS_MEMORY_NEW(Bubble, mm->pstate(), mm);
368   }
369
370   bool Cssize::bubblable(Statement_Ptr s)
371   {
372     return Cast<Ruleset>(s) || s->bubbles();
373   }
374
375   Block_Ptr Cssize::flatten(Block_Ptr b)
376   {
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));
384         }
385       }
386       else {
387         result->append(ss);
388       }
389     }
390     return result;
391   }
392
393   std::vector<std::pair<bool, Block_Obj>> Cssize::slice_by_bubble(Block_Ptr b)
394   {
395     std::vector<std::pair<bool, Block_Obj>> results;
396
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;
400
401       if (!results.empty() && results.back().first == key)
402       {
403         Block_Obj wrapper_block = results.back().second;
404         wrapper_block->append(value);
405       }
406       else
407       {
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));
411       }
412     }
413     return results;
414   }
415
416   Block_Ptr Cssize::debubble(Block_Ptr children, Statement_Ptr parent)
417   {
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());
421
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;
425
426       if (!is_bubble) {
427         if (!parent) {
428           result->append(slice);
429         }
430         else if (previous_parent) {
431           previous_parent->block()->concat(slice);
432         }
433         else {
434           previous_parent = Cast<Has_Block>(SASS_MEMORY_COPY(parent));
435           previous_parent->block(slice);
436           previous_parent->tabs(parent->tabs());
437
438           result->append(previous_parent);
439         }
440         continue;
441       }
442
443       for (size_t j = 0, K = slice->length(); j < K; ++j)
444       {
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());
453         if (!parent ||
454             parent->statement_type() != Statement::MEDIA ||
455             node->node()->statement_type() != Statement::MEDIA ||
456             (m1 && m2 && *m1->media_queries() == *m2->media_queries())
457           )
458         {
459           ss = node->node();
460         }
461         else
462         {
463           List_Obj mq = merge_media_queries(
464             Cast<Media_Block>(node->node()),
465             Cast<Media_Block>(parent)
466           );
467           if (!mq->length()) continue;
468           if (Media_Block* b = Cast<Media_Block>(node->node())) {
469             b->media_queries(mq);
470           }
471           ss = node->node();
472         }
473
474         if (!ss) continue;
475
476         ss->tabs(ss->tabs() + node->tabs());
477         ss->group_end(node->group_end());
478
479         if (!ss) continue;
480
481         Block_Obj bb = SASS_MEMORY_NEW(Block,
482                                     children->pstate(),
483                                     children->length(),
484                                     children->is_root());
485         bb->append(ss->perform(this));
486
487         Block_Obj wrapper_block = SASS_MEMORY_NEW(Block,
488                                               children->pstate(),
489                                               children->length(),
490                                               children->is_root());
491
492         Block_Ptr wrapper = flatten(bb);
493         wrapper_block->append(wrapper);
494
495         if (wrapper->length()) {
496           previous_parent = NULL;
497         }
498
499         if (wrapper_block) {
500           result->append(wrapper_block);
501         }
502       }
503     }
504
505     return flatten(result);
506   }
507
508   Statement_Ptr Cssize::fallback_impl(AST_Node_Ptr n)
509   {
510     return static_cast<Statement_Ptr>(n);
511   }
512
513   void Cssize::append_block(Block_Ptr b, Block_Ptr cur)
514   {
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));
520         }
521       }
522       else if (ith) {
523         cur->append(ith);
524       }
525     }
526   }
527
528   List_Ptr Cssize::merge_media_queries(Media_Block_Ptr m1, Media_Block_Ptr m2)
529   {
530     List_Ptr qq = SASS_MEMORY_NEW(List,
531                                m1->media_queries()->pstate(),
532                                m1->media_queries()->length(),
533                                SASS_COMMA);
534
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);
543       }
544     }
545
546     return qq;
547   }
548
549
550   Media_Query_Ptr Cssize::merge_media_query(Media_Query_Ptr mq1, Media_Query_Ptr mq2)
551   {
552
553     std::string type;
554     std::string mod;
555
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) : "";
560
561
562     if (t1.empty()) t1 = t2;
563     if (t2.empty()) t2 = t1;
564
565     if ((m1 == "not") ^ (m2 == "not")) {
566       if (t1 == t2) {
567         return 0;
568       }
569       type = m1 == "not" ? t2 : t1;
570       mod = m1 == "not" ? m2 : m1;
571     }
572     else if (m1 == "not" && m2 == "not") {
573       if (t1 != t2) {
574         return 0;
575       }
576       type = t1;
577       mod = "not";
578     }
579     else if (t1 != t2) {
580       return 0;
581     } else {
582       type = t1;
583       mod = m1.empty() ? m2 : m1;
584     }
585
586     Media_Query_Ptr mm = SASS_MEMORY_NEW(Media_Query,
587
588 mq1->pstate(), 0,
589 mq1->length() + mq2->length(), mod == "not", mod == "only"
590 );
591
592     if (!type.empty()) {
593       mm->media_type(SASS_MEMORY_NEW(String_Quoted, mq1->pstate(), type));
594     }
595
596     mm->concat(mq2);
597     mm->concat(mq1);
598
599     return mm;
600   }
601 }