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("[phony]")); 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