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
7namespace 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 // ##########################################################################
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("[phony]"));
24 for (auto complex : complexes) {
25 SelectorComponentObj base = complex.back();
26 if (CompoundSelector * comp = base->getCompound()) {
27 if (unifiedBase->empty()) {
28 unifiedBase->concat(v: 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(x: std::move(sel));
47 }
48
49 complexesWithoutBases.back().push_back(x: unifiedBase);
50
51 return weave(complexes: 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 // ##########################################################################
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 // ##########################################################################
82 CompoundSelector* SimpleSelector::unifyWith(CompoundSelector* rhs)
83 {
84
85 if (rhs->length() == 1) {
86 if (rhs->get(i: 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(i: 0)->unifyWith(rhs: 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(element: this);
107 addedThis = true;
108 }
109 result->append(element: simple);
110 }
111
112 if (!addedThis) {
113 result->append(element: 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 // ##########################################################################
123 CompoundSelector* TypeSelector::unifyWith(CompoundSelector* rhs)
124 {
125 if (rhs->empty()) {
126 rhs->append(element: this);
127 return rhs;
128 }
129 TypeSelector* type = Cast<TypeSelector>(ptr: rhs->at(i: 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(position: rhs->begin(), val: this);
139 }
140 return rhs;
141 }
142
143 // ##########################################################################
144 // This is implemented in `selector/id.dart` as `PseudoSelector::unify`
145 // ##########################################################################
146 CompoundSelector* IDSelector::unifyWith(CompoundSelector* rhs)
147 {
148 for (const SimpleSelector* sel : rhs->elements()) {
149 if (const IDSelector* id_sel = Cast<IDSelector>(ptr: 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 // ##########################################################################
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(element: this);
187 addedThis = true;
188 }
189 }
190 result->append(element: simple);
191 }
192
193 if (!addedThis) {
194 result->append(element: 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 // ##########################################################################
209 SimpleSelector* TypeSelector::unifyWith(const SimpleSelector* rhs)
210 {
211 bool rhs_ns = false;
212 if (!(is_ns_eq(r: *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(ns__: rhs->ns());
227 has_ns(has_ns__: rhs->has_ns());
228 }
229 if (rhs_name) 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 // ##########################################################################
238 SelectorList* ComplexSelector::unifyWith(ComplexSelector* rhs)
239 {
240 SelectorListObj list = SASS_MEMORY_NEW(SelectorList, pstate());
241 sass::vector<sass::vector<SelectorComponentObj>> rv =
242 unifyComplex(complexes: { 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(element: sel);
247 }
248 return list.detach();
249 }
250 // EO ComplexSelector::unifyWith(ComplexSelector*)
251
252 // ##########################################################################
253 // only called from the sass function `selector-unify`
254 // ##########################################################################
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(rhs: seq2)) {
263 std::move(first: unified->begin(), last: unified->end(),
264 result: std::inserter(x&: slist->elements(), i: slist->end()));
265 }
266 }
267 }
268 return slist;
269 }
270 // EO SelectorList::unifyWith(SelectorList*)
271
272 // ##########################################################################
273 // ##########################################################################
274
275}
276

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