1// sass.hpp must go before all system headers to get the
2// __EXTENSIONS__ fix on Solaris.
3#include "sass.hpp"
4
5#include "ast.hpp"
6#include "permutate.hpp"
7#include "util_string.hpp"
8
9namespace Sass {
10
11 /////////////////////////////////////////////////////////////////////////
12 /////////////////////////////////////////////////////////////////////////
13
14 Selector::Selector(SourceSpan pstate)
15 : Expression(pstate),
16 hash_(0)
17 { concrete_type(concrete_type__: SELECTOR); }
18
19 Selector::Selector(const Selector* ptr)
20 : Expression(ptr),
21 hash_(ptr->hash_)
22 { concrete_type(concrete_type__: SELECTOR); }
23
24
25 bool Selector::has_real_parent_ref() const
26 {
27 return false;
28 }
29
30 /////////////////////////////////////////////////////////////////////////
31 /////////////////////////////////////////////////////////////////////////
32
33 Selector_Schema::Selector_Schema(SourceSpan pstate, String_Obj c)
34 : AST_Node(pstate),
35 contents_(c),
36 connect_parent_(true),
37 hash_(0)
38 { }
39 Selector_Schema::Selector_Schema(const Selector_Schema* ptr)
40 : AST_Node(ptr),
41 contents_(ptr->contents_),
42 connect_parent_(ptr->connect_parent_),
43 hash_(ptr->hash_)
44 { }
45
46 unsigned long Selector_Schema::specificity() const
47 {
48 return 0;
49 }
50
51 size_t Selector_Schema::hash() const {
52 if (hash_ == 0) {
53 hash_combine(seed&: hash_, val: contents_->hash());
54 }
55 return hash_;
56 }
57
58 bool Selector_Schema::has_real_parent_ref() const
59 {
60 // Note: disabled since it does not seem to do anything?
61 // if (String_Schema_Obj schema = Cast<String_Schema>(contents())) {
62 // if (schema->empty()) return false;
63 // const auto first = schema->first();
64 // return Cast<Parent_Reference>(first);
65 // }
66 return false;
67 }
68
69 /////////////////////////////////////////////////////////////////////////
70 /////////////////////////////////////////////////////////////////////////
71
72 SimpleSelector::SimpleSelector(SourceSpan pstate, sass::string n)
73 : Selector(pstate), ns_(""), name_(n), has_ns_(false)
74 {
75 size_t pos = n.find(c: '|');
76 // found some namespace
77 if (pos != sass::string::npos) {
78 has_ns_ = true;
79 ns_ = n.substr(pos: 0, n: pos);
80 name_ = n.substr(pos: pos + 1);
81 }
82 }
83 SimpleSelector::SimpleSelector(const SimpleSelector* ptr)
84 : Selector(ptr),
85 ns_(ptr->ns_),
86 name_(ptr->name_),
87 has_ns_(ptr->has_ns_)
88 { }
89
90 sass::string SimpleSelector::ns_name() const
91 {
92 if (!has_ns_) return name_;
93 else return ns_ + "|" + name_;
94 }
95
96 size_t SimpleSelector::hash() const
97 {
98 if (hash_ == 0) {
99 hash_combine(seed&: hash_, val: name());
100 hash_combine(seed&: hash_, val: (int)SELECTOR);
101 hash_combine(seed&: hash_, val: (int)simple_type());
102 if (has_ns_) hash_combine(seed&: hash_, val: ns());
103 }
104 return hash_;
105 }
106
107 bool SimpleSelector::empty() const {
108 return ns().empty() && name().empty();
109 }
110
111 // namespace compare functions
112 bool SimpleSelector::is_ns_eq(const SimpleSelector& r) const
113 {
114 return has_ns_ == r.has_ns_ && ns_ == r.ns_;
115 }
116
117 // namespace query functions
118 bool SimpleSelector::is_universal_ns() const
119 {
120 return has_ns_ && ns_ == "*";
121 }
122
123 bool SimpleSelector::is_empty_ns() const
124 {
125 return !has_ns_ || ns_ == "";
126 }
127
128 bool SimpleSelector::has_empty_ns() const
129 {
130 return has_ns_ && ns_ == "";
131 }
132
133 bool SimpleSelector::has_qualified_ns() const
134 {
135 return has_ns_ && ns_ != "" && ns_ != "*";
136 }
137
138 // name query functions
139 bool SimpleSelector::is_universal() const
140 {
141 return name_ == "*";
142 }
143
144 bool SimpleSelector::has_placeholder()
145 {
146 return false;
147 }
148
149 bool SimpleSelector::has_real_parent_ref() const
150 {
151 return false;
152 };
153
154 bool SimpleSelector::is_pseudo_element() const
155 {
156 return false;
157 }
158
159 CompoundSelectorObj SimpleSelector::wrapInCompound()
160 {
161 CompoundSelectorObj selector =
162 SASS_MEMORY_NEW(CompoundSelector, pstate());
163 selector->append(element: this);
164 return selector;
165 }
166 ComplexSelectorObj SimpleSelector::wrapInComplex()
167 {
168 ComplexSelectorObj selector =
169 SASS_MEMORY_NEW(ComplexSelector, pstate());
170 selector->append(element: wrapInCompound());
171 return selector;
172 }
173
174 /////////////////////////////////////////////////////////////////////////
175 /////////////////////////////////////////////////////////////////////////
176
177 PlaceholderSelector::PlaceholderSelector(SourceSpan pstate, sass::string n)
178 : SimpleSelector(pstate, n)
179 { simple_type(simple_type__: PLACEHOLDER_SEL); }
180 PlaceholderSelector::PlaceholderSelector(const PlaceholderSelector* ptr)
181 : SimpleSelector(ptr)
182 { simple_type(simple_type__: PLACEHOLDER_SEL); }
183 unsigned long PlaceholderSelector::specificity() const
184 {
185 return Constants::Specificity_Base;
186 }
187 bool PlaceholderSelector::has_placeholder() {
188 return true;
189 }
190
191 /////////////////////////////////////////////////////////////////////////
192 /////////////////////////////////////////////////////////////////////////
193
194 TypeSelector::TypeSelector(SourceSpan pstate, sass::string n)
195 : SimpleSelector(pstate, n)
196 { simple_type(simple_type__: TYPE_SEL); }
197 TypeSelector::TypeSelector(const TypeSelector* ptr)
198 : SimpleSelector(ptr)
199 { simple_type(simple_type__: TYPE_SEL); }
200
201 unsigned long TypeSelector::specificity() const
202 {
203 if (name() == "*") return 0;
204 else return Constants::Specificity_Element;
205 }
206
207 /////////////////////////////////////////////////////////////////////////
208 /////////////////////////////////////////////////////////////////////////
209
210 ClassSelector::ClassSelector(SourceSpan pstate, sass::string n)
211 : SimpleSelector(pstate, n)
212 { simple_type(simple_type__: CLASS_SEL); }
213 ClassSelector::ClassSelector(const ClassSelector* ptr)
214 : SimpleSelector(ptr)
215 { simple_type(simple_type__: CLASS_SEL); }
216
217 unsigned long ClassSelector::specificity() const
218 {
219 return Constants::Specificity_Class;
220 }
221
222 /////////////////////////////////////////////////////////////////////////
223 /////////////////////////////////////////////////////////////////////////
224
225 IDSelector::IDSelector(SourceSpan pstate, sass::string n)
226 : SimpleSelector(pstate, n)
227 { simple_type(simple_type__: ID_SEL); }
228 IDSelector::IDSelector(const IDSelector* ptr)
229 : SimpleSelector(ptr)
230 { simple_type(simple_type__: ID_SEL); }
231
232 unsigned long IDSelector::specificity() const
233 {
234 return Constants::Specificity_ID;
235 }
236
237 /////////////////////////////////////////////////////////////////////////
238 /////////////////////////////////////////////////////////////////////////
239
240 AttributeSelector::AttributeSelector(SourceSpan pstate, sass::string n, sass::string m, String_Obj v, char o)
241 : SimpleSelector(pstate, n), matcher_(m), value_(v), modifier_(o)
242 { simple_type(simple_type__: ATTRIBUTE_SEL); }
243 AttributeSelector::AttributeSelector(const AttributeSelector* ptr)
244 : SimpleSelector(ptr),
245 matcher_(ptr->matcher_),
246 value_(ptr->value_),
247 modifier_(ptr->modifier_)
248 { simple_type(simple_type__: ATTRIBUTE_SEL); }
249
250 size_t AttributeSelector::hash() const
251 {
252 if (hash_ == 0) {
253 hash_combine(seed&: hash_, val: SimpleSelector::hash());
254 hash_combine(seed&: hash_, val: std::hash<sass::string>()(matcher()));
255 if (value_) hash_combine(seed&: hash_, val: value_->hash());
256 }
257 return hash_;
258 }
259
260 unsigned long AttributeSelector::specificity() const
261 {
262 return Constants::Specificity_Attr;
263 }
264
265 /////////////////////////////////////////////////////////////////////////
266 /////////////////////////////////////////////////////////////////////////
267
268 PseudoSelector::PseudoSelector(SourceSpan pstate, sass::string name, bool element)
269 : SimpleSelector(pstate, name),
270 normalized_(Util::unvendor(name)),
271 argument_({}),
272 selector_({}),
273 isSyntacticClass_(!element),
274 isClass_(!element && !isFakePseudoElement(name: normalized_))
275 { simple_type(simple_type__: PSEUDO_SEL); }
276 PseudoSelector::PseudoSelector(const PseudoSelector* ptr)
277 : SimpleSelector(ptr),
278 normalized_(ptr->normalized()),
279 argument_(ptr->argument()),
280 selector_(ptr->selector()),
281 isSyntacticClass_(ptr->isSyntacticClass()),
282 isClass_(ptr->isClass())
283 { simple_type(simple_type__: PSEUDO_SEL); }
284
285 // A pseudo-element is made of two colons (::) followed by the name.
286 // The `::` notation is introduced by the current document in order to
287 // establish a discrimination between pseudo-classes and pseudo-elements.
288 // For compatibility with existing style sheets, user agents must also
289 // accept the previous one-colon notation for pseudo-elements introduced
290 // in CSS levels 1 and 2 (namely, :first-line, :first-letter, :before and
291 // :after). This compatibility is not allowed for the new pseudo-elements
292 // introduced in this specification.
293 bool PseudoSelector::is_pseudo_element() const
294 {
295 return isElement();
296 }
297
298 size_t PseudoSelector::hash() const
299 {
300 if (hash_ == 0) {
301 hash_combine(seed&: hash_, val: SimpleSelector::hash());
302 if (selector_) hash_combine(seed&: hash_, val: selector_->hash());
303 if (argument_) hash_combine(seed&: hash_, val: argument_->hash());
304 }
305 return hash_;
306 }
307
308 unsigned long PseudoSelector::specificity() const
309 {
310 if (is_pseudo_element())
311 return Constants::Specificity_Element;
312 return Constants::Specificity_Pseudo;
313 }
314
315 PseudoSelectorObj PseudoSelector::withSelector(SelectorListObj selector)
316 {
317 PseudoSelectorObj pseudo = SASS_MEMORY_COPY(this);
318 pseudo->selector(selector__: selector);
319 return pseudo;
320 }
321
322 bool PseudoSelector::empty() const
323 {
324 // Only considered empty if selector is
325 // available but has no items in it.
326 return selector() && selector()->empty();
327 }
328
329 void PseudoSelector::cloneChildren()
330 {
331 if (selector().isNull()) selector(selector__: {});
332 else selector(SASS_MEMORY_CLONE(selector()));
333 }
334
335 bool PseudoSelector::has_real_parent_ref() const {
336 if (!selector()) return false;
337 return selector()->has_real_parent_ref();
338 }
339
340 /////////////////////////////////////////////////////////////////////////
341 /////////////////////////////////////////////////////////////////////////
342
343 SelectorList::SelectorList(SourceSpan pstate, size_t s)
344 : Selector(pstate),
345 Vectorized<ComplexSelectorObj>(s),
346 is_optional_(false)
347 { }
348 SelectorList::SelectorList(const SelectorList* ptr)
349 : Selector(ptr),
350 Vectorized<ComplexSelectorObj>(*ptr),
351 is_optional_(ptr->is_optional_)
352 { }
353
354 size_t SelectorList::hash() const
355 {
356 if (Selector::hash_ == 0) {
357 hash_combine(seed&: Selector::hash_, val: Vectorized::hash());
358 }
359 return Selector::hash_;
360 }
361
362 bool SelectorList::has_real_parent_ref() const
363 {
364 for (ComplexSelectorObj s : elements()) {
365 if (s && s->has_real_parent_ref()) return true;
366 }
367 return false;
368 }
369
370 void SelectorList::cloneChildren()
371 {
372 for (size_t i = 0, l = length(); i < l; i++) {
373 at(i) = SASS_MEMORY_CLONE(at(i));
374 }
375 }
376
377 unsigned long SelectorList::specificity() const
378 {
379 return 0;
380 }
381
382 bool SelectorList::isInvisible() const
383 {
384 if (length() == 0) return true;
385 for (size_t i = 0; i < length(); i += 1) {
386 if (get(i)->isInvisible()) return true;
387 }
388 return false;
389 }
390
391 /////////////////////////////////////////////////////////////////////////
392 /////////////////////////////////////////////////////////////////////////
393
394 ComplexSelector::ComplexSelector(SourceSpan pstate)
395 : Selector(pstate),
396 Vectorized<SelectorComponentObj>(),
397 chroots_(false),
398 hasPreLineFeed_(false)
399 {
400 }
401 ComplexSelector::ComplexSelector(const ComplexSelector* ptr)
402 : Selector(ptr),
403 Vectorized<SelectorComponentObj>(ptr->elements()),
404 chroots_(ptr->chroots()),
405 hasPreLineFeed_(ptr->hasPreLineFeed())
406 {
407 }
408
409 void ComplexSelector::cloneChildren()
410 {
411 for (size_t i = 0, l = length(); i < l; i++) {
412 at(i) = SASS_MEMORY_CLONE(at(i));
413 }
414 }
415
416 unsigned long ComplexSelector::specificity() const
417 {
418 int sum = 0;
419 for (auto component : elements()) {
420 sum += component->specificity();
421 }
422 return sum;
423 }
424
425 bool ComplexSelector::isInvisible() const
426 {
427 if (length() == 0) return true;
428 for (size_t i = 0; i < length(); i += 1) {
429 if (CompoundSelectorObj compound = get(i)->getCompound()) {
430 if (compound->isInvisible()) return true;
431 }
432 }
433 return false;
434 }
435
436 SelectorListObj ComplexSelector::wrapInList()
437 {
438 SelectorListObj selector =
439 SASS_MEMORY_NEW(SelectorList, pstate());
440 selector->append(element: this);
441 return selector;
442 }
443
444 size_t ComplexSelector::hash() const
445 {
446 if (Selector::hash_ == 0) {
447 hash_combine(seed&: Selector::hash_, val: Vectorized::hash());
448 // ToDo: this breaks some extend lookup
449 // hash_combine(Selector::hash_, chroots_);
450 }
451 return Selector::hash_;
452 }
453
454 bool ComplexSelector::has_placeholder() const {
455 for (size_t i = 0, L = length(); i < L; ++i) {
456 if (get(i)->has_placeholder()) return true;
457 }
458 return false;
459 }
460
461 bool ComplexSelector::has_real_parent_ref() const
462 {
463 for (auto item : elements()) {
464 if (item->has_real_parent_ref()) return true;
465 }
466 return false;
467 }
468
469 /////////////////////////////////////////////////////////////////////////
470 /////////////////////////////////////////////////////////////////////////
471
472 SelectorComponent::SelectorComponent(SourceSpan pstate, bool postLineBreak)
473 : Selector(pstate),
474 hasPostLineBreak_(postLineBreak)
475 {
476 }
477
478 SelectorComponent::SelectorComponent(const SelectorComponent* ptr)
479 : Selector(ptr),
480 hasPostLineBreak_(ptr->hasPostLineBreak())
481 { }
482
483 void SelectorComponent::cloneChildren()
484 {
485 }
486
487 unsigned long SelectorComponent::specificity() const
488 {
489 return 0;
490 }
491
492 // Wrap the compound selector with a complex selector
493 ComplexSelector* SelectorComponent::wrapInComplex()
494 {
495 auto complex = SASS_MEMORY_NEW(ComplexSelector, pstate());
496 complex->append(element: this);
497 return complex;
498 }
499
500 /////////////////////////////////////////////////////////////////////////
501 /////////////////////////////////////////////////////////////////////////
502
503 SelectorCombinator::SelectorCombinator(SourceSpan pstate, SelectorCombinator::Combinator combinator, bool postLineBreak)
504 : SelectorComponent(pstate, postLineBreak),
505 combinator_(combinator)
506 {
507 }
508 SelectorCombinator::SelectorCombinator(const SelectorCombinator* ptr)
509 : SelectorComponent(ptr->pstate(), false),
510 combinator_(ptr->combinator())
511 { }
512
513 void SelectorCombinator::cloneChildren()
514 {
515 }
516
517 unsigned long SelectorCombinator::specificity() const
518 {
519 return 0;
520 }
521
522 /////////////////////////////////////////////////////////////////////////
523 /////////////////////////////////////////////////////////////////////////
524
525 CompoundSelector::CompoundSelector(SourceSpan pstate, bool postLineBreak)
526 : SelectorComponent(pstate, postLineBreak),
527 Vectorized<SimpleSelectorObj>(),
528 hasRealParent_(false),
529 extended_(false)
530 {
531 }
532 CompoundSelector::CompoundSelector(const CompoundSelector* ptr)
533 : SelectorComponent(ptr),
534 Vectorized<SimpleSelectorObj>(*ptr),
535 hasRealParent_(ptr->hasRealParent()),
536 extended_(ptr->extended())
537 { }
538
539 size_t CompoundSelector::hash() const
540 {
541 if (Selector::hash_ == 0) {
542 hash_combine(seed&: Selector::hash_, val: Vectorized::hash());
543 hash_combine(seed&: Selector::hash_, val: hasRealParent_);
544 }
545 return Selector::hash_;
546 }
547
548 bool CompoundSelector::has_real_parent_ref() const
549 {
550 if (hasRealParent()) return true;
551 // ToDo: dart sass has another check?
552 // if (Cast<TypeSelector>(front)) {
553 // if (front->ns() != "") return false;
554 // }
555 for (const SimpleSelector* s : elements()) {
556 if (s && s->has_real_parent_ref()) return true;
557 }
558 return false;
559 }
560
561 bool CompoundSelector::has_placeholder() const
562 {
563 if (length() == 0) return false;
564 for (SimpleSelectorObj ss : elements()) {
565 if (ss->has_placeholder()) return true;
566 }
567 return false;
568 }
569
570 void CompoundSelector::cloneChildren()
571 {
572 for (size_t i = 0, l = length(); i < l; i++) {
573 at(i) = SASS_MEMORY_CLONE(at(i));
574 }
575 }
576
577 unsigned long CompoundSelector::specificity() const
578 {
579 int sum = 0;
580 for (size_t i = 0, L = length(); i < L; ++i)
581 { sum += get(i)->specificity(); }
582 return sum;
583 }
584
585 bool CompoundSelector::isInvisible() const
586 {
587 for (size_t i = 0; i < length(); i += 1) {
588 if (!get(i)->isInvisible()) return false;
589 }
590 return true;
591 }
592
593 bool CompoundSelector::isSuperselectorOf(const CompoundSelector* sub, sass::string wrapped) const
594 {
595 CompoundSelector* rhs2 = const_cast<CompoundSelector*>(sub);
596 CompoundSelector* lhs2 = const_cast<CompoundSelector*>(this);
597 return compoundIsSuperselector(compound1: lhs2, compound2: rhs2, parents: {});
598 }
599
600 /////////////////////////////////////////////////////////////////////////
601 /////////////////////////////////////////////////////////////////////////
602
603 MediaRule::MediaRule(SourceSpan pstate, Block_Obj block) :
604 ParentStatement(pstate, block),
605 schema_({})
606 {
607 statement_type(statement_type__: MEDIA);
608 }
609
610 MediaRule::MediaRule(const MediaRule* ptr) :
611 ParentStatement(ptr),
612 schema_(ptr->schema_)
613 {
614 statement_type(statement_type__: MEDIA);
615 }
616
617 /////////////////////////////////////////////////////////////////////////
618 /////////////////////////////////////////////////////////////////////////
619
620 CssMediaRule::CssMediaRule(SourceSpan pstate, Block_Obj block) :
621 ParentStatement(pstate, block),
622 Vectorized()
623 {
624 statement_type(statement_type__: MEDIA);
625 }
626
627 CssMediaRule::CssMediaRule(const CssMediaRule* ptr) :
628 ParentStatement(ptr),
629 Vectorized(*ptr)
630 {
631 statement_type(statement_type__: MEDIA);
632 }
633
634 CssMediaQuery::CssMediaQuery(SourceSpan pstate) :
635 AST_Node(pstate),
636 modifier_(""),
637 type_(""),
638 features_()
639 {
640 }
641
642 /////////////////////////////////////////////////////////////////////////
643 /////////////////////////////////////////////////////////////////////////
644
645 bool CssMediaQuery::operator==(const CssMediaQuery& rhs) const
646 {
647 return type_ == rhs.type_
648 && modifier_ == rhs.modifier_
649 && features_ == rhs.features_;
650 }
651
652 // Implemented after dart-sass (maybe move to other class?)
653 CssMediaQuery_Obj CssMediaQuery::merge(CssMediaQuery_Obj& other)
654 {
655
656 sass::string ourType = this->type();
657 Util::ascii_str_tolower(s: &ourType);
658
659 sass::string theirType = other->type();
660 Util::ascii_str_tolower(s: &theirType);
661
662 sass::string ourModifier = this->modifier();
663 Util::ascii_str_tolower(s: &ourModifier);
664
665 sass::string theirModifier = other->modifier();
666 Util::ascii_str_tolower(s: &theirModifier);
667
668 sass::string type;
669 sass::string modifier;
670 sass::vector<sass::string> features;
671
672 if (ourType.empty() && theirType.empty()) {
673 CssMediaQuery_Obj query = SASS_MEMORY_NEW(CssMediaQuery, pstate());
674 sass::vector<sass::string> f1(this->features());
675 sass::vector<sass::string> f2(other->features());
676 features.insert(position: features.end(), first: f1.begin(), last: f1.end());
677 features.insert(position: features.end(), first: f2.begin(), last: f2.end());
678 query->features(features__: features);
679 return query;
680 }
681
682 if ((ourModifier == "not") != (theirModifier == "not")) {
683 if (ourType == theirType) {
684 sass::vector<sass::string> negativeFeatures =
685 ourModifier == "not" ? this->features() : other->features();
686 sass::vector<sass::string> positiveFeatures =
687 ourModifier == "not" ? other->features() : this->features();
688
689 // If the negative features are a subset of the positive features, the
690 // query is empty. For example, `not screen and (color)` has no
691 // intersection with `screen and (color) and (grid)`.
692 // However, `not screen and (color)` *does* intersect with `screen and
693 // (grid)`, because it means `not (screen and (color))` and so it allows
694 // a screen with no color but with a grid.
695 if (listIsSubsetOrEqual(lhs: negativeFeatures, rhs: positiveFeatures)) {
696 return SASS_MEMORY_NEW(CssMediaQuery, pstate());
697 }
698 else {
699 return {};
700 }
701 }
702 else if (this->matchesAllTypes() || other->matchesAllTypes()) {
703 return {};
704 }
705
706 if (ourModifier == "not") {
707 modifier = theirModifier;
708 type = theirType;
709 features = other->features();
710 }
711 else {
712 modifier = ourModifier;
713 type = ourType;
714 features = this->features();
715 }
716 }
717 else if (ourModifier == "not") {
718 SASS_ASSERT(theirModifier == "not", "modifiers not is sync");
719
720 // CSS has no way of representing "neither screen nor print".
721 if (ourType != theirType) return {};
722
723 auto moreFeatures = this->features().size() > other->features().size()
724 ? this->features()
725 : other->features();
726 auto fewerFeatures = this->features().size() > other->features().size()
727 ? other->features()
728 : this->features();
729
730 // If one set of features is a superset of the other,
731 // use those features because they're strictly narrower.
732 if (listIsSubsetOrEqual(lhs: fewerFeatures, rhs: moreFeatures)) {
733 modifier = ourModifier; // "not"
734 type = ourType;
735 features = moreFeatures;
736 }
737 else {
738 // Otherwise, there's no way to
739 // represent the intersection.
740 return {};
741 }
742
743 }
744 else {
745 if (this->matchesAllTypes()) {
746 modifier = theirModifier;
747 // Omit the type if either input query did, since that indicates that they
748 // aren't targeting a browser that requires "all and".
749 type = (other->matchesAllTypes() && ourType.empty()) ? "" : theirType;
750 sass::vector<sass::string> f1(this->features());
751 sass::vector<sass::string> f2(other->features());
752 features.insert(position: features.end(), first: f1.begin(), last: f1.end());
753 features.insert(position: features.end(), first: f2.begin(), last: f2.end());
754 }
755 else if (other->matchesAllTypes()) {
756 modifier = ourModifier;
757 type = ourType;
758 sass::vector<sass::string> f1(this->features());
759 sass::vector<sass::string> f2(other->features());
760 features.insert(position: features.end(), first: f1.begin(), last: f1.end());
761 features.insert(position: features.end(), first: f2.begin(), last: f2.end());
762 }
763 else if (ourType != theirType) {
764 return SASS_MEMORY_NEW(CssMediaQuery, pstate());
765 }
766 else {
767 modifier = ourModifier.empty() ? theirModifier : ourModifier;
768 type = ourType;
769 sass::vector<sass::string> f1(this->features());
770 sass::vector<sass::string> f2(other->features());
771 features.insert(position: features.end(), first: f1.begin(), last: f1.end());
772 features.insert(position: features.end(), first: f2.begin(), last: f2.end());
773 }
774 }
775
776 CssMediaQuery_Obj query = SASS_MEMORY_NEW(CssMediaQuery, pstate());
777 query->modifier(modifier__: modifier == ourModifier ? this->modifier() : other->modifier());
778 query->type(type__: ourType.empty() ? other->type() : this->type());
779 query->features(features__: features);
780 return query;
781 }
782
783 CssMediaQuery::CssMediaQuery(const CssMediaQuery* ptr) :
784 AST_Node(*ptr),
785 modifier_(ptr->modifier_),
786 type_(ptr->type_),
787 features_(ptr->features_)
788 {
789 }
790
791 /////////////////////////////////////////////////////////////////////////
792 // ToDo: finalize specificity implementation
793 /////////////////////////////////////////////////////////////////////////
794
795 size_t SelectorList::maxSpecificity() const
796 {
797 size_t specificity = 0;
798 for (auto complex : elements()) {
799 specificity = std::max(a: specificity, b: complex->maxSpecificity());
800 }
801 return specificity;
802 }
803
804 size_t SelectorList::minSpecificity() const
805 {
806 size_t specificity = 0;
807 for (auto complex : elements()) {
808 specificity = std::min(a: specificity, b: complex->minSpecificity());
809 }
810 return specificity;
811 }
812
813 size_t CompoundSelector::maxSpecificity() const
814 {
815 size_t specificity = 0;
816 for (auto simple : elements()) {
817 specificity += simple->maxSpecificity();
818 }
819 return specificity;
820 }
821
822 size_t CompoundSelector::minSpecificity() const
823 {
824 size_t specificity = 0;
825 for (auto simple : elements()) {
826 specificity += simple->minSpecificity();
827 }
828 return specificity;
829 }
830
831 size_t ComplexSelector::maxSpecificity() const
832 {
833 size_t specificity = 0;
834 for (auto component : elements()) {
835 specificity += component->maxSpecificity();
836 }
837 return specificity;
838 }
839
840 size_t ComplexSelector::minSpecificity() const
841 {
842 size_t specificity = 0;
843 for (auto component : elements()) {
844 specificity += component->minSpecificity();
845 }
846 return specificity;
847 }
848
849 /////////////////////////////////////////////////////////////////////////
850 // ToDo: this might be done easier with new selector format
851 /////////////////////////////////////////////////////////////////////////
852
853 sass::vector<ComplexSelectorObj>
854 CompoundSelector::resolve_parent_refs(SelectorStack pstack, Backtraces& traces, bool implicit_parent)
855 {
856
857 auto parent = pstack.back();
858 sass::vector<ComplexSelectorObj> rv;
859
860 for (SimpleSelectorObj simple : elements()) {
861 if (PseudoSelector * pseudo = Cast<PseudoSelector>(ptr: simple)) {
862 if (SelectorList* sel = Cast<SelectorList>(ptr: pseudo->selector())) {
863 if (parent) {
864 pseudo->selector(selector__: sel->resolve_parent_refs(
865 pstack, traces, implicit_parent));
866 }
867 }
868 }
869 }
870
871 // Mix with parents from stack
872 if (hasRealParent()) {
873
874 if (parent.isNull()) {
875 return { wrapInComplex() };
876 }
877 else {
878 for (auto complex : parent->elements()) {
879 // The parent complex selector has a compound selector
880 if (CompoundSelectorObj tail = Cast<CompoundSelector>(ptr: complex->last())) {
881 // Create a copy to alter it
882 complex = SASS_MEMORY_COPY(complex);
883 tail = SASS_MEMORY_COPY(tail);
884
885 // Check if we can merge front with back
886 if (length() > 0 && tail->length() > 0) {
887 SimpleSelectorObj back = tail->last();
888 SimpleSelectorObj front = first();
889 auto simple_back = Cast<SimpleSelector>(ptr: back);
890 auto simple_front = Cast<TypeSelector>(ptr: front);
891 if (simple_front && simple_back) {
892 simple_back = SASS_MEMORY_COPY(simple_back);
893 auto name = simple_back->name();
894 name += simple_front->name();
895 simple_back->name(name__: name);
896 tail->elements().back() = simple_back;
897 tail->elements().insert(position: tail->end(),
898 first: begin() + 1, last: end());
899 }
900 else {
901 tail->concat(v: this);
902 }
903 }
904 else {
905 tail->concat(v: this);
906 }
907
908 complex->elements().back() = tail;
909 // Append to results
910 rv.push_back(x: complex);
911 }
912 else {
913 // Can't insert parent that ends with a combinator
914 // where the parent selector is followed by something
915 if (parent && length() > 0) {
916 throw Exception::InvalidParent(parent, traces, this);
917 }
918 // Create a copy to alter it
919 complex = SASS_MEMORY_COPY(complex);
920 // Just append ourself
921 complex->append(element: this);
922 // Append to results
923 rv.push_back(x: complex);
924 }
925 }
926 }
927 }
928
929 // No parents
930 else {
931 // Create a new wrapper to wrap ourself
932 auto complex = SASS_MEMORY_NEW(ComplexSelector, pstate());
933 // Just append ourself
934 complex->append(element: this);
935 // Append to results
936 rv.push_back(x: complex);
937 }
938
939 return rv;
940
941 }
942
943 bool cmpSimpleSelectors(SimpleSelector* a, SimpleSelector* b)
944 {
945 return (a->getSortOrder() < b->getSortOrder());
946 }
947
948 void CompoundSelector::sortChildren()
949 {
950 std::sort(first: begin(), last: end(), comp: cmpSimpleSelectors);
951 }
952
953 /* better return sass::vector? only - is empty container anyway? */
954 SelectorList* ComplexSelector::resolve_parent_refs(SelectorStack pstack, Backtraces& traces, bool implicit_parent)
955 {
956
957 sass::vector<sass::vector<ComplexSelectorObj>> vars;
958
959 auto parent = pstack.back();
960
961 if (has_real_parent_ref() && !parent) {
962 throw Exception::TopLevelParent(traces, pstate());
963 }
964
965 if (!chroots() && parent) {
966
967 if (!has_real_parent_ref() && !implicit_parent) {
968 SelectorList* retval = SASS_MEMORY_NEW(SelectorList, pstate(), 1);
969 retval->append(element: this);
970 return retval;
971 }
972
973 vars.push_back(x: parent->elements());
974 }
975
976 for (auto sel : elements()) {
977 if (CompoundSelectorObj comp = Cast<CompoundSelector>(ptr: sel)) {
978 auto asd = comp->resolve_parent_refs(pstack, traces, implicit_parent);
979 if (asd.size() > 0) vars.push_back(x: asd);
980 }
981 else {
982 // ToDo: merge together sequences whenever possible
983 auto cont = SASS_MEMORY_NEW(ComplexSelector, pstate());
984 cont->append(element: sel);
985 vars.push_back(x: { cont });
986 }
987 }
988
989 // Need complex selectors to preserve linefeeds
990 sass::vector<sass::vector<ComplexSelectorObj>> res = permutateAlt(in: vars);
991
992 // std::reverse(std::begin(res), std::end(res));
993
994 auto lst = SASS_MEMORY_NEW(SelectorList, pstate());
995 for (auto items : res) {
996 if (items.size() > 0) {
997 ComplexSelectorObj first = SASS_MEMORY_COPY(items[0]);
998 first->hasPreLineFeed(hasPreLineFeed__: first->hasPreLineFeed() || (!has_real_parent_ref() && hasPreLineFeed()));
999 // ToDo: remove once we know how to handle line feeds
1000 // ToDo: currently a mashup between ruby and dart sass
1001 // if (has_real_parent_ref()) first->has_line_feed(false);
1002 // first->has_line_break(first->has_line_break() || has_line_break());
1003 first->chroots(chroots__: true); // has been resolved by now
1004 for (size_t i = 1; i < items.size(); i += 1) {
1005 first->concat(v: items[i]);
1006 }
1007 lst->append(element: first);
1008 }
1009 }
1010
1011 return lst;
1012
1013 }
1014
1015 SelectorList* SelectorList::resolve_parent_refs(SelectorStack pstack, Backtraces& traces, bool implicit_parent)
1016 {
1017 SelectorList* rv = SASS_MEMORY_NEW(SelectorList, pstate());
1018 for (auto sel : elements()) {
1019 // Note: this one is tricky as we get back a pointer from resolve parents ...
1020 SelectorListObj res = sel->resolve_parent_refs(pstack, traces, implicit_parent);
1021 // Note: ... and concat will only append the items in elements
1022 // Therefore by passing it directly, the container will leak!
1023 rv->concat(v: res);
1024 }
1025 return rv;
1026 }
1027
1028 /////////////////////////////////////////////////////////////////////////
1029 /////////////////////////////////////////////////////////////////////////
1030
1031 IMPLEMENT_AST_OPERATORS(Selector_Schema);
1032 IMPLEMENT_AST_OPERATORS(PlaceholderSelector);
1033 IMPLEMENT_AST_OPERATORS(AttributeSelector);
1034 IMPLEMENT_AST_OPERATORS(TypeSelector);
1035 IMPLEMENT_AST_OPERATORS(ClassSelector);
1036 IMPLEMENT_AST_OPERATORS(IDSelector);
1037 IMPLEMENT_AST_OPERATORS(PseudoSelector);
1038 IMPLEMENT_AST_OPERATORS(SelectorCombinator);
1039 IMPLEMENT_AST_OPERATORS(CompoundSelector);
1040 IMPLEMENT_AST_OPERATORS(ComplexSelector);
1041 IMPLEMENT_AST_OPERATORS(SelectorList);
1042
1043}
1044

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