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 
7 namespace Sass {
8 
9   // ##########################################################################
10   // Returns the contents of a [SelectorList] that matches only
11   // elements that are matched by both [complex1] and [complex2].
12   // If no such list can be produced, returns `null`.
13   // ##########################################################################
14   // ToDo: fine-tune API to avoid unnecessary wrapper allocations
15   // ##########################################################################
unifyComplex(const sass::vector<sass::vector<SelectorComponentObj>> & complexes)16   sass::vector<sass::vector<SelectorComponentObj>> unifyComplex(
17     const sass::vector<sass::vector<SelectorComponentObj>>& complexes)
18   {
19 
20     SASS_ASSERT(!complexes.empty(), "Can't unify empty list");
21     if (complexes.size() == 1) return complexes;
22 
23     CompoundSelectorObj unifiedBase = SASS_MEMORY_NEW(CompoundSelector, SourceSpan("[unify]"));
24     for (auto complex : complexes) {
25       SelectorComponentObj base = complex.back();
26       if (CompoundSelector * comp = base->getCompound()) {
27         if (unifiedBase->empty()) {
28           unifiedBase->concat(comp);
29         }
30         else {
31           for (SimpleSelectorObj simple : comp->elements()) {
32             unifiedBase = simple->unifyWith(unifiedBase);
33             if (unifiedBase.isNull()) return {};
34           }
35         }
36       }
37       else {
38         return {};
39       }
40     }
41 
42     sass::vector<sass::vector<SelectorComponentObj>> complexesWithoutBases;
43     for (size_t i = 0; i < complexes.size(); i += 1) {
44       sass::vector<SelectorComponentObj> sel = complexes[i];
45       sel.pop_back(); // remove last item (base) from the list
46       complexesWithoutBases.push_back(std::move(sel));
47     }
48 
49     complexesWithoutBases.back().push_back(unifiedBase);
50 
51     return weave(complexesWithoutBases);
52 
53   }
54   // EO unifyComplex
55 
56   // ##########################################################################
57   // Returns a [CompoundSelector] that matches only elements
58   // that are matched by both [compound1] and [compound2].
59   // If no such selector can be produced, returns `null`.
60   // ##########################################################################
unifyWith(CompoundSelector * rhs)61   CompoundSelector* CompoundSelector::unifyWith(CompoundSelector* rhs)
62   {
63     if (empty()) return rhs;
64     CompoundSelectorObj unified = SASS_MEMORY_COPY(rhs);
65     for (const SimpleSelectorObj& sel : elements()) {
66       unified = sel->unifyWith(unified);
67       if (unified.isNull()) break;
68     }
69     return unified.detach();
70   }
71   // EO CompoundSelector::unifyWith(CompoundSelector*)
72 
73   // ##########################################################################
74   // Returns the compoments of a [CompoundSelector] that matches only elements
75   // matched by both this and [compound]. By default, this just returns a copy
76   // of [compound] with this selector added to the end, or returns the original
77   // array if this selector already exists in it. Returns `null` if unification
78   // is impossible—for example, if there are multiple ID selectors.
79   // ##########################################################################
80   // This is implemented in `selector/simple.dart` as `SimpleSelector::unify`
81   // ##########################################################################
unifyWith(CompoundSelector * rhs)82   CompoundSelector* SimpleSelector::unifyWith(CompoundSelector* rhs)
83   {
84 
85     if (rhs->length() == 1) {
86       if (rhs->get(0)->is_universal()) {
87         CompoundSelector* this_compound = SASS_MEMORY_NEW(CompoundSelector, pstate());
88         this_compound->append(SASS_MEMORY_COPY(this));
89         CompoundSelector* unified = rhs->get(0)->unifyWith(this_compound);
90         if (unified == nullptr || unified != this_compound) delete this_compound;
91         return unified;
92       }
93     }
94     for (const SimpleSelectorObj& sel : rhs->elements()) {
95       if (*this == *sel) {
96         return rhs;
97       }
98     }
99 
100     CompoundSelectorObj result = SASS_MEMORY_NEW(CompoundSelector, rhs->pstate());
101 
102     bool addedThis = false;
103     for (auto simple : rhs->elements()) {
104       // Make sure pseudo selectors always come last.
105       if (!addedThis && simple->getPseudoSelector()) {
106         result->append(this);
107         addedThis = true;
108       }
109       result->append(simple);
110     }
111 
112     if (!addedThis) {
113       result->append(this);
114     }
115     return result.detach();
116 
117   }
118   // EO SimpleSelector::unifyWith(CompoundSelector*)
119 
120   // ##########################################################################
121   // This is implemented in `selector/type.dart` as `PseudoSelector::unify`
122   // ##########################################################################
unifyWith(CompoundSelector * rhs)123   CompoundSelector* TypeSelector::unifyWith(CompoundSelector* rhs)
124   {
125     if (rhs->empty()) {
126       rhs->append(this);
127       return rhs;
128     }
129     TypeSelector* type = Cast<TypeSelector>(rhs->at(0));
130     if (type != nullptr) {
131       SimpleSelector* unified = unifyWith(type);
132       if (unified == nullptr) {
133         return nullptr;
134       }
135       rhs->elements()[0] = unified;
136     }
137     else if (!is_universal() || (has_ns_ && ns_ != "*")) {
138       rhs->insert(rhs->begin(), this);
139     }
140     return rhs;
141   }
142 
143   // ##########################################################################
144   // This is implemented in `selector/id.dart` as `PseudoSelector::unify`
145   // ##########################################################################
unifyWith(CompoundSelector * rhs)146   CompoundSelector* IDSelector::unifyWith(CompoundSelector* rhs)
147   {
148     for (const SimpleSelector* sel : rhs->elements()) {
149       if (const IDSelector* id_sel = Cast<IDSelector>(sel)) {
150         if (id_sel->name() != name()) return nullptr;
151       }
152     }
153     return SimpleSelector::unifyWith(rhs);
154   }
155 
156   // ##########################################################################
157   // This is implemented in `selector/pseudo.dart` as `PseudoSelector::unify`
158   // ##########################################################################
unifyWith(CompoundSelector * compound)159   CompoundSelector* PseudoSelector::unifyWith(CompoundSelector* compound)
160   {
161 
162     if (compound->length() == 1 && compound->first()->is_universal()) {
163       // std::cerr << "implement universal pseudo\n";
164     }
165 
166     for (const SimpleSelectorObj& sel : compound->elements()) {
167       if (*this == *sel) {
168         return compound;
169       }
170     }
171 
172     CompoundSelectorObj result = SASS_MEMORY_NEW(CompoundSelector, compound->pstate());
173 
174     bool addedThis = false;
175     for (auto simple : compound->elements()) {
176       // Make sure pseudo selectors always come last.
177       if (PseudoSelectorObj pseudo = simple->getPseudoSelector()) {
178         if (pseudo->isElement()) {
179           // A given compound selector may only contain one pseudo element. If
180           // [compound] has a different one than [this], unification fails.
181           if (isElement()) {
182             return {};
183           }
184           // Otherwise, this is a pseudo selector and
185           // should come before pseduo elements.
186           result->append(this);
187           addedThis = true;
188         }
189       }
190       result->append(simple);
191     }
192 
193     if (!addedThis) {
194       result->append(this);
195     }
196 
197     return result.detach();
198 
199   }
200   // EO PseudoSelector::unifyWith(CompoundSelector*
201 
202   // ##########################################################################
203   // This is implemented in `extend/functions.dart` as `unifyUniversalAndElement`
204   // Returns a [SimpleSelector] that matches only elements that are matched by
205   // both [selector1] and [selector2], which must both be either [UniversalSelector]s
206   // or [TypeSelector]s. If no such selector can be produced, returns `null`.
207   // Note: libsass handles universal selector directly within the type selector
208   // ##########################################################################
unifyWith(const SimpleSelector * rhs)209   SimpleSelector* TypeSelector::unifyWith(const SimpleSelector* rhs)
210   {
211     bool rhs_ns = false;
212     if (!(is_ns_eq(*rhs) || rhs->is_universal_ns())) {
213       if (!is_universal_ns()) {
214         return nullptr;
215       }
216       rhs_ns = true;
217     }
218     bool rhs_name = false;
219     if (!(name_ == rhs->name() || rhs->is_universal())) {
220       if (!(is_universal())) {
221         return nullptr;
222       }
223       rhs_name = true;
224     }
225     if (rhs_ns) {
226       ns(rhs->ns());
227       has_ns(rhs->has_ns());
228     }
229     if (rhs_name) name(rhs->name());
230     return this;
231   }
232   // EO TypeSelector::unifyWith(const SimpleSelector*)
233 
234   // ##########################################################################
235   // Unify two complex selectors. Internally calls `unifyComplex`
236   // and then wraps the result in newly create ComplexSelectors.
237   // ##########################################################################
unifyWith(ComplexSelector * rhs)238   SelectorList* ComplexSelector::unifyWith(ComplexSelector* rhs)
239   {
240     SelectorListObj list = SASS_MEMORY_NEW(SelectorList, pstate());
241     sass::vector<sass::vector<SelectorComponentObj>> rv =
242        unifyComplex({ elements(), rhs->elements() });
243     for (sass::vector<SelectorComponentObj> items : rv) {
244       ComplexSelectorObj sel = SASS_MEMORY_NEW(ComplexSelector, pstate());
245       sel->elements() = std::move(items);
246       list->append(sel);
247     }
248     return list.detach();
249   }
250   // EO ComplexSelector::unifyWith(ComplexSelector*)
251 
252   // ##########################################################################
253   // only called from the sass function `selector-unify`
254   // ##########################################################################
unifyWith(SelectorList * rhs)255   SelectorList* SelectorList::unifyWith(SelectorList* rhs)
256   {
257     SelectorList* slist = SASS_MEMORY_NEW(SelectorList, pstate());
258     // Unify all of children with RHS's children,
259     // storing the results in `unified_complex_selectors`
260     for (ComplexSelectorObj& seq1 : elements()) {
261       for (ComplexSelectorObj& seq2 : rhs->elements()) {
262         if (SelectorListObj unified = seq1->unifyWith(seq2)) {
263           std::move(unified->begin(), unified->end(),
264             std::inserter(slist->elements(), slist->end()));
265         }
266       }
267     }
268     return slist;
269   }
270   // EO SelectorList::unifyWith(SelectorList*)
271 
272   // ##########################################################################
273   // ##########################################################################
274 
275 }
276