1// sass.hpp must go before all system headers to get the
2// __EXTENSIONS__ fix on Solaris.
3#include "sass.hpp"
4
5#include <iostream>
6#include <typeinfo>
7#include <vector>
8
9#include "cssize.hpp"
10#include "context.hpp"
11
12namespace Sass {
13
14 Cssize::Cssize(Context& ctx)
15 : traces(ctx.traces),
16 block_stack(BlockStack()),
17 p_stack(sass::vector<Statement*>())
18 { }
19
20 Statement* Cssize::parent()
21 {
22 return p_stack.size() ? p_stack.back() : block_stack.front();
23 }
24
25 Block* Cssize::operator()(Block* b)
26 {
27 Block_Obj bb = SASS_MEMORY_NEW(Block, b->pstate(), b->length(), b->is_root());
28 // bb->tabs(b->tabs());
29 block_stack.push_back(x: bb);
30 append_block(b, bb);
31 block_stack.pop_back();
32 return bb.detach();
33 }
34
35 Statement* Cssize::operator()(Trace* t)
36 {
37 traces.push_back(x: Backtrace(t->pstate()));
38 auto result = t->block()->perform(op: this);
39 traces.pop_back();
40 return result;
41 }
42
43 Statement* Cssize::operator()(Declaration* d)
44 {
45 String_Obj property = Cast<String>(ptr: d->property());
46
47 if (Declaration* dd = Cast<Declaration>(ptr: parent())) {
48 String_Obj parent_property = Cast<String>(ptr: dd->property());
49 property = SASS_MEMORY_NEW(String_Constant,
50 d->property()->pstate(),
51 parent_property->to_string() + "-" + property->to_string());
52 if (!dd->value()) {
53 d->tabs(tabs__: dd->tabs() + 1);
54 }
55 }
56
57 Declaration_Obj dd = SASS_MEMORY_NEW(Declaration,
58 d->pstate(),
59 property,
60 d->value(),
61 d->is_important(),
62 d->is_custom_property());
63 dd->is_indented(is_indented__: d->is_indented());
64 dd->tabs(tabs__: d->tabs());
65
66 p_stack.push_back(x: dd);
67 Block_Obj bb = d->block() ? operator()(b: d->block()) : NULL;
68 p_stack.pop_back();
69
70 if (bb && bb->length()) {
71 if (dd->value() && !dd->value()->is_invisible()) {
72 bb->unshift(element: dd);
73 }
74 return bb.detach();
75 }
76 else if (dd->value() && !dd->value()->is_invisible()) {
77 return dd.detach();
78 }
79
80 return 0;
81 }
82
83 Statement* Cssize::operator()(AtRule* r)
84 {
85 if (!r->block() || !r->block()->length()) return r;
86
87 if (parent()->statement_type() == Statement::RULESET)
88 {
89 return r->is_keyframes() ? SASS_MEMORY_NEW(Bubble, r->pstate(), r) : bubble(r);
90 }
91
92 p_stack.push_back(x: r);
93 AtRuleObj rr = SASS_MEMORY_NEW(AtRule,
94 r->pstate(),
95 r->keyword(),
96 r->selector(),
97 r->block() ? operator()(r->block()) : 0);
98 if (r->value()) rr->value(value__: r->value());
99 p_stack.pop_back();
100
101 bool directive_exists = false;
102 size_t L = rr->block() ? rr->block()->length() : 0;
103 for (size_t i = 0; i < L && !directive_exists; ++i) {
104 Statement_Obj s = r->block()->at(i);
105 if (s->statement_type() != Statement::BUBBLE) directive_exists = true;
106 else {
107 Bubble_Obj s_obj = Cast<Bubble>(ptr: s);
108 s = s_obj->node();
109 if (s->statement_type() != Statement::DIRECTIVE) directive_exists = false;
110 else directive_exists = (Cast<AtRule>(ptr: s)->keyword() == rr->keyword());
111 }
112
113 }
114
115 Block* result = SASS_MEMORY_NEW(Block, rr->pstate());
116 if (!(directive_exists || rr->is_keyframes()))
117 {
118 AtRule* empty_node = Cast<AtRule>(ptr: rr);
119 empty_node->block(SASS_MEMORY_NEW(Block, rr->block() ? rr->block()->pstate() : rr->pstate()));
120 result->append(element: empty_node);
121 }
122
123 Block_Obj db = rr->block();
124 if (db.isNull()) db = SASS_MEMORY_NEW(Block, rr->pstate());
125 Block_Obj ss = debubble(children: db, parent: rr);
126 for (size_t i = 0, L = ss->length(); i < L; ++i) {
127 result->append(element: ss->at(i));
128 }
129
130 return result;
131 }
132
133 Statement* Cssize::operator()(Keyframe_Rule* r)
134 {
135 if (!r->block() || !r->block()->length()) return r;
136
137 Keyframe_Rule_Obj rr = SASS_MEMORY_NEW(Keyframe_Rule,
138 r->pstate(),
139 operator()(r->block()));
140 if (!r->name().isNull()) rr->name(name__: r->name());
141
142 return debubble(children: rr->block(), parent: rr);
143 }
144
145 Statement* Cssize::operator()(StyleRule* r)
146 {
147 p_stack.push_back(x: r);
148 // this can return a string schema
149 // string schema is not a statement!
150 // r->block() is already a string schema
151 // and that is coming from propset expand
152 Block* bb = operator()(b: r->block());
153 // this should protect us (at least a bit) from our mess
154 // fixing this properly is harder that it should be ...
155 if (Cast<Statement>(ptr: bb) == NULL) {
156 error(msg: "Illegal nesting: Only properties may be nested beneath properties.", pstate: r->block()->pstate(), traces);
157 }
158 StyleRuleObj rr = SASS_MEMORY_NEW(StyleRule,
159 r->pstate(),
160 r->selector(),
161 bb);
162
163 rr->is_root(is_root__: r->is_root());
164 // rr->tabs(r->block()->tabs());
165 p_stack.pop_back();
166
167 if (!rr->block()) {
168 error(msg: "Illegal nesting: Only properties may be nested beneath properties.", pstate: r->block()->pstate(), traces);
169 }
170
171 Block_Obj props = SASS_MEMORY_NEW(Block, rr->block()->pstate());
172 Block* rules = SASS_MEMORY_NEW(Block, rr->block()->pstate());
173 for (size_t i = 0, L = rr->block()->length(); i < L; i++)
174 {
175 Statement* s = rr->block()->at(i);
176 if (bubblable(s)) rules->append(element: s);
177 if (!bubblable(s)) props->append(element: s);
178 }
179
180 if (props->length())
181 {
182 Block_Obj pb = SASS_MEMORY_NEW(Block, rr->block()->pstate());
183 pb->concat(v: props);
184 rr->block(block__: pb);
185
186 for (size_t i = 0, L = rules->length(); i < L; i++)
187 {
188 Statement* stm = rules->at(i);
189 stm->tabs(tabs__: stm->tabs() + 1);
190 }
191
192 rules->unshift(element: rr);
193 }
194
195 Block* ptr = rules;
196 rules = debubble(children: rules);
197 void* lp = ptr;
198 void* rp = rules;
199 if (lp != rp) {
200 Block_Obj obj = ptr;
201 }
202
203 if (!(!rules->length() ||
204 !bubblable(rules->last()) ||
205 parent()->statement_type() == Statement::RULESET))
206 {
207 rules->last()->group_end(group_end__: true);
208 }
209 return rules;
210 }
211
212 Statement* Cssize::operator()(Null* m)
213 {
214 return 0;
215 }
216
217 Statement* Cssize::operator()(CssMediaRule* m)
218 {
219 if (parent()->statement_type() == Statement::RULESET)
220 {
221 return bubble(m);
222 }
223
224 if (parent()->statement_type() == Statement::MEDIA)
225 {
226 return SASS_MEMORY_NEW(Bubble, m->pstate(), m);
227 }
228
229 p_stack.push_back(x: m);
230
231 CssMediaRuleObj mm = SASS_MEMORY_NEW(CssMediaRule, m->pstate(), m->block());
232 mm->concat(v: m->elements());
233 mm->block(block__: operator()(b: m->block()));
234 mm->tabs(tabs__: m->tabs());
235
236 p_stack.pop_back();
237
238 return debubble(children: mm->block(), parent: mm);
239 }
240
241 Statement* Cssize::operator()(SupportsRule* m)
242 {
243 if (!m->block()->length())
244 { return m; }
245
246 if (parent()->statement_type() == Statement::RULESET)
247 { return bubble(m); }
248
249 p_stack.push_back(x: m);
250
251 SupportsRuleObj mm = SASS_MEMORY_NEW(SupportsRule,
252 m->pstate(),
253 m->condition(),
254 operator()(m->block()));
255 mm->tabs(tabs__: m->tabs());
256
257 p_stack.pop_back();
258
259 return debubble(children: mm->block(), parent: mm);
260 }
261
262 Statement* Cssize::operator()(AtRootRule* m)
263 {
264 bool tmp = false;
265 for (size_t i = 0, L = p_stack.size(); i < L; ++i) {
266 Statement* s = p_stack[i];
267 tmp |= m->exclude_node(s);
268 }
269
270 if (!tmp && m->block())
271 {
272 Block* bb = operator()(b: m->block());
273 for (size_t i = 0, L = bb->length(); i < L; ++i) {
274 // (bb->elements())[i]->tabs(m->tabs());
275 Statement_Obj stm = bb->at(i);
276 if (bubblable(stm)) stm->tabs(tabs__: stm->tabs() + m->tabs());
277 }
278 if (bb->length() && bubblable(bb->last())) bb->last()->group_end(group_end__: m->group_end());
279 return bb;
280 }
281
282 if (m->exclude_node(s: parent()))
283 {
284 return SASS_MEMORY_NEW(Bubble, m->pstate(), m);
285 }
286
287 return bubble(m);
288 }
289
290 Statement* Cssize::bubble(AtRule* m)
291 {
292 Block* bb = SASS_MEMORY_NEW(Block, this->parent()->pstate());
293 ParentStatementObj new_rule = Cast<ParentStatement>(SASS_MEMORY_COPY(this->parent()));
294 new_rule->block(block__: bb);
295 new_rule->tabs(tabs__: this->parent()->tabs());
296 new_rule->block()->concat(v: m->block());
297
298 Block_Obj wrapper_block = SASS_MEMORY_NEW(Block, m->block() ? m->block()->pstate() : m->pstate());
299 wrapper_block->append(element: new_rule);
300 AtRuleObj mm = SASS_MEMORY_NEW(AtRule,
301 m->pstate(),
302 m->keyword(),
303 m->selector(),
304 wrapper_block);
305 if (m->value()) mm->value(value__: m->value());
306
307 Bubble* bubble = SASS_MEMORY_NEW(Bubble, mm->pstate(), mm);
308 return bubble;
309 }
310
311 Statement* Cssize::bubble(AtRootRule* m)
312 {
313 if (!m || !m->block()) return NULL;
314 Block* bb = SASS_MEMORY_NEW(Block, this->parent()->pstate());
315 ParentStatementObj new_rule = Cast<ParentStatement>(SASS_MEMORY_COPY(this->parent()));
316 Block* wrapper_block = SASS_MEMORY_NEW(Block, m->block()->pstate());
317 if (new_rule) {
318 new_rule->block(block__: bb);
319 new_rule->tabs(tabs__: this->parent()->tabs());
320 new_rule->block()->concat(v: m->block());
321 wrapper_block->append(element: new_rule);
322 }
323
324 AtRootRule* mm = SASS_MEMORY_NEW(AtRootRule,
325 m->pstate(),
326 wrapper_block,
327 m->expression());
328 Bubble* bubble = SASS_MEMORY_NEW(Bubble, mm->pstate(), mm);
329 return bubble;
330 }
331
332 Statement* Cssize::bubble(SupportsRule* m)
333 {
334 StyleRuleObj parent = Cast<StyleRule>(SASS_MEMORY_COPY(this->parent()));
335
336 Block* bb = SASS_MEMORY_NEW(Block, parent->block()->pstate());
337 StyleRule* new_rule = SASS_MEMORY_NEW(StyleRule,
338 parent->pstate(),
339 parent->selector(),
340 bb);
341 new_rule->tabs(tabs__: parent->tabs());
342 new_rule->block()->concat(v: m->block());
343
344 Block* wrapper_block = SASS_MEMORY_NEW(Block, m->block()->pstate());
345 wrapper_block->append(element: new_rule);
346 SupportsRule* mm = SASS_MEMORY_NEW(SupportsRule,
347 m->pstate(),
348 m->condition(),
349 wrapper_block);
350
351 mm->tabs(tabs__: m->tabs());
352
353 Bubble* bubble = SASS_MEMORY_NEW(Bubble, mm->pstate(), mm);
354 return bubble;
355 }
356
357 Statement* Cssize::bubble(CssMediaRule* m)
358 {
359 StyleRuleObj parent = Cast<StyleRule>(SASS_MEMORY_COPY(this->parent()));
360
361 Block* bb = SASS_MEMORY_NEW(Block, parent->block()->pstate());
362 StyleRule* new_rule = SASS_MEMORY_NEW(StyleRule,
363 parent->pstate(),
364 parent->selector(),
365 bb);
366 new_rule->tabs(tabs__: parent->tabs());
367 new_rule->block()->concat(v: m->block());
368
369 Block* wrapper_block = SASS_MEMORY_NEW(Block, m->block()->pstate());
370 wrapper_block->append(element: new_rule);
371 CssMediaRuleObj mm = SASS_MEMORY_NEW(CssMediaRule,
372 m->pstate(),
373 wrapper_block);
374 mm->concat(v: m->elements());
375
376 mm->tabs(tabs__: m->tabs());
377
378 return SASS_MEMORY_NEW(Bubble, mm->pstate(), mm);
379 }
380
381 bool Cssize::bubblable(Statement* s)
382 {
383 return Cast<StyleRule>(ptr: s) || (s && s->bubbles());
384 }
385
386 Block* Cssize::flatten(const Block* b)
387 {
388 Block* result = SASS_MEMORY_NEW(Block, b->pstate(), 0, b->is_root());
389 for (size_t i = 0, L = b->length(); i < L; ++i) {
390 Statement* ss = b->at(i);
391 if (const Block* bb = Cast<Block>(ptr: ss)) {
392 Block_Obj bs = flatten(b: bb);
393 for (size_t j = 0, K = bs->length(); j < K; ++j) {
394 result->append(element: bs->at(i: j));
395 }
396 }
397 else {
398 result->append(element: ss);
399 }
400 }
401 return result;
402 }
403
404 sass::vector<std::pair<bool, Block_Obj>> Cssize::slice_by_bubble(Block* b)
405 {
406 sass::vector<std::pair<bool, Block_Obj>> results;
407
408 for (size_t i = 0, L = b->length(); i < L; ++i) {
409 Statement_Obj value = b->at(i);
410 bool key = Cast<Bubble>(ptr: value) != NULL;
411
412 if (!results.empty() && results.back().first == key)
413 {
414 Block_Obj wrapper_block = results.back().second;
415 wrapper_block->append(element: value);
416 }
417 else
418 {
419 Block* wrapper_block = SASS_MEMORY_NEW(Block, value->pstate());
420 wrapper_block->append(element: value);
421 results.push_back(x: std::make_pair(x&: key, y&: wrapper_block));
422 }
423 }
424 return results;
425 }
426
427 Block* Cssize::debubble(Block* children, Statement* parent)
428 {
429 ParentStatementObj previous_parent;
430 sass::vector<std::pair<bool, Block_Obj>> baz = slice_by_bubble(b: children);
431 Block_Obj result = SASS_MEMORY_NEW(Block, children->pstate());
432
433 for (size_t i = 0, L = baz.size(); i < L; ++i) {
434 bool is_bubble = baz[i].first;
435 Block_Obj slice = baz[i].second;
436
437 if (!is_bubble) {
438 if (!parent) {
439 result->append(element: slice);
440 }
441 else if (previous_parent) {
442 previous_parent->block()->concat(v: slice);
443 }
444 else {
445 previous_parent = SASS_MEMORY_COPY(parent);
446 previous_parent->block(block__: slice);
447 previous_parent->tabs(tabs__: parent->tabs());
448
449 result->append(element: previous_parent);
450 }
451 continue;
452 }
453
454 for (size_t j = 0, K = slice->length(); j < K; ++j)
455 {
456 Statement_Obj ss;
457 Statement_Obj stm = slice->at(i: j);
458 // this has to go now here (too bad)
459 Bubble_Obj node = Cast<Bubble>(ptr: stm);
460
461 CssMediaRule* rule1 = NULL;
462 CssMediaRule* rule2 = NULL;
463 if (parent) rule1 = Cast<CssMediaRule>(ptr: parent);
464 if (node) rule2 = Cast<CssMediaRule>(ptr: node->node());
465 if (rule1 || rule2) {
466 ss = node->node();
467 }
468
469 ss = node->node();
470
471 if (!ss) {
472 continue;
473 }
474
475 ss->tabs(tabs__: ss->tabs() + node->tabs());
476 ss->group_end(group_end__: node->group_end());
477
478 Block_Obj bb = SASS_MEMORY_NEW(Block,
479 children->pstate(),
480 children->length(),
481 children->is_root());
482 auto evaled = ss->perform(op: this);
483 if (evaled) bb->append(element: evaled);
484
485 Block_Obj wrapper_block = SASS_MEMORY_NEW(Block,
486 children->pstate(),
487 children->length(),
488 children->is_root());
489
490 Block* wrapper = flatten(b: bb);
491 wrapper_block->append(element: wrapper);
492
493 if (wrapper->length()) {
494 previous_parent = {};
495 }
496
497 if (wrapper_block) {
498 result->append(element: wrapper_block);
499 }
500 }
501 }
502
503 return flatten(b: result);
504 }
505
506 void Cssize::append_block(Block* b, Block* cur)
507 {
508 for (size_t i = 0, L = b->length(); i < L; ++i) {
509 Statement_Obj ith = b->at(i)->perform(op: this);
510 if (Block_Obj bb = Cast<Block>(ptr: ith)) {
511 for (size_t j = 0, K = bb->length(); j < K; ++j) {
512 cur->append(element: bb->at(i: j));
513 }
514 }
515 else if (ith) {
516 cur->append(element: ith);
517 }
518 }
519 }
520
521}
522

source code of gtk/subprojects/libsass/src/cssize.cpp