1 | #ifndef SASS_AST_SEL_H |
2 | #define SASS_AST_SEL_H |
3 | |
4 | // sass.hpp must go before all system headers to get the |
5 | // __EXTENSIONS__ fix on Solaris. |
6 | #include "sass.hpp" |
7 | #include "ast.hpp" |
8 | |
9 | namespace Sass { |
10 | |
11 | ///////////////////////////////////////////////////////////////////////// |
12 | // Some helper functions |
13 | ///////////////////////////////////////////////////////////////////////// |
14 | |
15 | bool compoundIsSuperselector( |
16 | const CompoundSelectorObj& compound1, |
17 | const CompoundSelectorObj& compound2, |
18 | const sass::vector<SelectorComponentObj>& parents); |
19 | |
20 | bool complexIsParentSuperselector( |
21 | const sass::vector<SelectorComponentObj>& complex1, |
22 | const sass::vector<SelectorComponentObj>& complex2); |
23 | |
24 | sass::vector<sass::vector<SelectorComponentObj>> weave( |
25 | const sass::vector<sass::vector<SelectorComponentObj>>& complexes); |
26 | |
27 | sass::vector<sass::vector<SelectorComponentObj>> weaveParents( |
28 | sass::vector<SelectorComponentObj> parents1, |
29 | sass::vector<SelectorComponentObj> parents2); |
30 | |
31 | sass::vector<SimpleSelectorObj> unifyCompound( |
32 | const sass::vector<SimpleSelectorObj>& compound1, |
33 | const sass::vector<SimpleSelectorObj>& compound2); |
34 | |
35 | sass::vector<sass::vector<SelectorComponentObj>> unifyComplex( |
36 | const sass::vector<sass::vector<SelectorComponentObj>>& complexes); |
37 | |
38 | ///////////////////////////////////////// |
39 | // Abstract base class for CSS selectors. |
40 | ///////////////////////////////////////// |
41 | class Selector : public Expression { |
42 | protected: |
43 | mutable size_t hash_; |
44 | public: |
45 | Selector(SourceSpan pstate); |
46 | virtual ~Selector() = 0; |
47 | size_t hash() const override = 0; |
48 | virtual bool has_real_parent_ref() const; |
49 | // you should reset this to null on containers |
50 | virtual unsigned long specificity() const = 0; |
51 | // by default we return the regular specificity |
52 | // you must override this for all containers |
53 | virtual size_t maxSpecificity() const { return specificity(); } |
54 | virtual size_t minSpecificity() const { return specificity(); } |
55 | // dispatch to correct handlers |
56 | ATTACH_VIRTUAL_CMP_OPERATIONS(Selector) |
57 | ATTACH_VIRTUAL_AST_OPERATIONS(Selector) |
58 | }; |
59 | inline Selector::~Selector() { } |
60 | |
61 | ///////////////////////////////////////////////////////////////////////// |
62 | // Interpolated selectors -- the interpolated String will be expanded and |
63 | // re-parsed into a normal selector class. |
64 | ///////////////////////////////////////////////////////////////////////// |
65 | class Selector_Schema final : public AST_Node { |
66 | ADD_PROPERTY(String_Schema_Obj, contents) |
67 | ADD_PROPERTY(bool, connect_parent); |
68 | // store computed hash |
69 | mutable size_t hash_; |
70 | public: |
71 | Selector_Schema(SourceSpan pstate, String_Obj c); |
72 | |
73 | bool has_real_parent_ref() const; |
74 | // selector schema is not yet a final selector, so we do not |
75 | // have a specificity for it yet. We need to |
76 | virtual unsigned long specificity() const; |
77 | size_t hash() const override; |
78 | ATTACH_AST_OPERATIONS(Selector_Schema) |
79 | ATTACH_CRTP_PERFORM_METHODS() |
80 | }; |
81 | |
82 | //////////////////////////////////////////// |
83 | // Abstract base class for simple selectors. |
84 | //////////////////////////////////////////// |
85 | class SimpleSelector : public Selector { |
86 | public: |
87 | enum Simple_Type { |
88 | ID_SEL, |
89 | TYPE_SEL, |
90 | CLASS_SEL, |
91 | PSEUDO_SEL, |
92 | ATTRIBUTE_SEL, |
93 | PLACEHOLDER_SEL, |
94 | }; |
95 | public: |
96 | HASH_CONSTREF(sass::string, ns) |
97 | HASH_CONSTREF(sass::string, name) |
98 | ADD_PROPERTY(Simple_Type, simple_type) |
99 | HASH_PROPERTY(bool, has_ns) |
100 | public: |
101 | SimpleSelector(SourceSpan pstate, sass::string n = "" ); |
102 | // ordering within parent (peudos go last) |
103 | virtual int getSortOrder() const = 0; |
104 | virtual sass::string ns_name() const; |
105 | size_t hash() const override; |
106 | virtual bool empty() const; |
107 | // namespace compare functions |
108 | bool is_ns_eq(const SimpleSelector& r) const; |
109 | // namespace query functions |
110 | bool is_universal_ns() const; |
111 | bool is_empty_ns() const; |
112 | bool has_empty_ns() const; |
113 | bool has_qualified_ns() const; |
114 | // name query functions |
115 | bool is_universal() const; |
116 | virtual bool has_placeholder(); |
117 | |
118 | virtual ~SimpleSelector() = 0; |
119 | virtual CompoundSelector* unifyWith(CompoundSelector*); |
120 | |
121 | /* helper function for syntax sugar */ |
122 | virtual IDSelector* getIdSelector() { return NULL; } |
123 | virtual TypeSelector* getTypeSelector() { return NULL; } |
124 | virtual PseudoSelector* getPseudoSelector() { return NULL; } |
125 | |
126 | ComplexSelectorObj wrapInComplex(); |
127 | CompoundSelectorObj wrapInCompound(); |
128 | |
129 | virtual bool isInvisible() const { return false; } |
130 | virtual bool is_pseudo_element() const; |
131 | virtual bool has_real_parent_ref() const override; |
132 | |
133 | bool operator==(const Selector& rhs) const final override; |
134 | |
135 | virtual bool operator==(const SelectorList& rhs) const; |
136 | virtual bool operator==(const ComplexSelector& rhs) const; |
137 | virtual bool operator==(const CompoundSelector& rhs) const; |
138 | |
139 | ATTACH_VIRTUAL_CMP_OPERATIONS(SimpleSelector); |
140 | ATTACH_VIRTUAL_AST_OPERATIONS(SimpleSelector); |
141 | ATTACH_CRTP_PERFORM_METHODS(); |
142 | |
143 | }; |
144 | inline SimpleSelector::~SimpleSelector() { } |
145 | |
146 | ///////////////////////////////////////////////////////////////////////// |
147 | // Placeholder selectors (e.g., "%foo") for use in extend-only selectors. |
148 | ///////////////////////////////////////////////////////////////////////// |
149 | class PlaceholderSelector final : public SimpleSelector { |
150 | public: |
151 | PlaceholderSelector(SourceSpan pstate, sass::string n); |
152 | int getSortOrder() const override final { return 0; } |
153 | bool isInvisible() const override { return true; } |
154 | virtual unsigned long specificity() const override; |
155 | virtual bool has_placeholder() override; |
156 | bool operator==(const SimpleSelector& rhs) const override; |
157 | ATTACH_CMP_OPERATIONS(PlaceholderSelector) |
158 | ATTACH_AST_OPERATIONS(PlaceholderSelector) |
159 | ATTACH_CRTP_PERFORM_METHODS() |
160 | }; |
161 | |
162 | ///////////////////////////////////////////////////////////////////// |
163 | // Type selectors (and the universal selector) -- e.g., div, span, *. |
164 | ///////////////////////////////////////////////////////////////////// |
165 | class TypeSelector final : public SimpleSelector { |
166 | public: |
167 | TypeSelector(SourceSpan pstate, sass::string n); |
168 | int getSortOrder() const override final { return 1; } |
169 | virtual unsigned long specificity() const override; |
170 | SimpleSelector* unifyWith(const SimpleSelector*); |
171 | CompoundSelector* unifyWith(CompoundSelector*) override; |
172 | TypeSelector* getTypeSelector() override { return this; } |
173 | bool operator==(const SimpleSelector& rhs) const final override; |
174 | ATTACH_CMP_OPERATIONS(TypeSelector) |
175 | ATTACH_AST_OPERATIONS(TypeSelector) |
176 | ATTACH_CRTP_PERFORM_METHODS() |
177 | }; |
178 | |
179 | //////////////////////////////////////////////// |
180 | // Class selectors -- i.e., .foo. |
181 | //////////////////////////////////////////////// |
182 | class ClassSelector final : public SimpleSelector { |
183 | public: |
184 | ClassSelector(SourceSpan pstate, sass::string n); |
185 | int getSortOrder() const override final { return 3; } |
186 | virtual unsigned long specificity() const override; |
187 | bool operator==(const SimpleSelector& rhs) const final override; |
188 | ATTACH_CMP_OPERATIONS(ClassSelector) |
189 | ATTACH_AST_OPERATIONS(ClassSelector) |
190 | ATTACH_CRTP_PERFORM_METHODS() |
191 | }; |
192 | |
193 | //////////////////////////////////////////////// |
194 | // ID selectors -- i.e., #foo. |
195 | //////////////////////////////////////////////// |
196 | class IDSelector final : public SimpleSelector { |
197 | public: |
198 | IDSelector(SourceSpan pstate, sass::string n); |
199 | int getSortOrder() const override final { return 2; } |
200 | virtual unsigned long specificity() const override; |
201 | CompoundSelector* unifyWith(CompoundSelector*) override; |
202 | IDSelector* getIdSelector() final override { return this; } |
203 | bool operator==(const SimpleSelector& rhs) const final override; |
204 | ATTACH_CMP_OPERATIONS(IDSelector) |
205 | ATTACH_AST_OPERATIONS(IDSelector) |
206 | ATTACH_CRTP_PERFORM_METHODS() |
207 | }; |
208 | |
209 | /////////////////////////////////////////////////// |
210 | // Attribute selectors -- e.g., [src*=".jpg"], etc. |
211 | /////////////////////////////////////////////////// |
212 | class AttributeSelector final : public SimpleSelector { |
213 | ADD_CONSTREF(sass::string, matcher) |
214 | // this cannot be changed to obj atm!!!!!!????!!!!!!! |
215 | ADD_PROPERTY(String_Obj, value) // might be interpolated |
216 | ADD_PROPERTY(char, modifier); |
217 | public: |
218 | AttributeSelector(SourceSpan pstate, sass::string n, sass::string m, String_Obj v, char o = 0); |
219 | int getSortOrder() const override final { return 4; } |
220 | size_t hash() const override; |
221 | virtual unsigned long specificity() const override; |
222 | bool operator==(const SimpleSelector& rhs) const final override; |
223 | ATTACH_CMP_OPERATIONS(AttributeSelector) |
224 | ATTACH_AST_OPERATIONS(AttributeSelector) |
225 | ATTACH_CRTP_PERFORM_METHODS() |
226 | }; |
227 | |
228 | ////////////////////////////////////////////////////////////////// |
229 | // Pseudo selectors -- e.g., :first-child, :nth-of-type(...), etc. |
230 | ////////////////////////////////////////////////////////////////// |
231 | // Pseudo Selector cannot have any namespace? |
232 | class PseudoSelector final : public SimpleSelector { |
233 | ADD_PROPERTY(sass::string, normalized) |
234 | ADD_PROPERTY(String_Obj, argument) |
235 | ADD_PROPERTY(SelectorListObj, selector) |
236 | ADD_PROPERTY(bool, isSyntacticClass) |
237 | ADD_PROPERTY(bool, isClass) |
238 | public: |
239 | PseudoSelector(SourceSpan pstate, sass::string n, bool element = false); |
240 | int getSortOrder() const override final { return 5; } |
241 | virtual bool is_pseudo_element() const override; |
242 | size_t hash() const override; |
243 | |
244 | bool empty() const override; |
245 | |
246 | bool has_real_parent_ref() const override; |
247 | |
248 | // Whether this is a pseudo-element selector. |
249 | // This is `true` if and only if [isClass] is `false`. |
250 | bool isElement() const { return !isClass(); } |
251 | |
252 | // Whether this is syntactically a pseudo-element selector. |
253 | // This is `true` if and only if [isSyntacticClass] is `false`. |
254 | bool isSyntacticElement() const { return !isSyntacticClass(); } |
255 | |
256 | virtual unsigned long specificity() const override; |
257 | PseudoSelectorObj withSelector(SelectorListObj selector); |
258 | |
259 | CompoundSelector* unifyWith(CompoundSelector*) override; |
260 | PseudoSelector* getPseudoSelector() final override { return this; } |
261 | bool operator==(const SimpleSelector& rhs) const final override; |
262 | ATTACH_CMP_OPERATIONS(PseudoSelector) |
263 | ATTACH_AST_OPERATIONS(PseudoSelector) |
264 | void cloneChildren() override; |
265 | ATTACH_CRTP_PERFORM_METHODS() |
266 | }; |
267 | |
268 | |
269 | //////////////////////////////////////////////////////////////////////////// |
270 | // Complex Selectors are the most important class of selectors. |
271 | // A Selector List consists of Complex Selectors (separated by comma) |
272 | // Complex Selectors are itself a list of Compounds and Combinators |
273 | // Between each item there is an implicit ancestor of combinator |
274 | //////////////////////////////////////////////////////////////////////////// |
275 | class ComplexSelector final : public Selector, public Vectorized<SelectorComponentObj> { |
276 | ADD_PROPERTY(bool, chroots) |
277 | // line break before list separator |
278 | ADD_PROPERTY(bool, hasPreLineFeed) |
279 | public: |
280 | ComplexSelector(SourceSpan pstate); |
281 | |
282 | // Returns true if the first components |
283 | // is a compound selector and fullfills |
284 | // a few other criteria. |
285 | bool isInvisible() const; |
286 | |
287 | size_t hash() const override; |
288 | void cloneChildren() override; |
289 | bool has_placeholder() const; |
290 | bool has_real_parent_ref() const override; |
291 | |
292 | SelectorList* resolve_parent_refs(SelectorStack pstack, Backtraces& traces, bool implicit_parent = true); |
293 | virtual unsigned long specificity() const override; |
294 | |
295 | SelectorList* unifyWith(ComplexSelector* rhs); |
296 | |
297 | bool isSuperselectorOf(const ComplexSelector* sub) const; |
298 | |
299 | SelectorListObj wrapInList(); |
300 | |
301 | size_t maxSpecificity() const override; |
302 | size_t minSpecificity() const override; |
303 | |
304 | bool operator==(const Selector& rhs) const override; |
305 | bool operator==(const SelectorList& rhs) const; |
306 | bool operator==(const CompoundSelector& rhs) const; |
307 | bool operator==(const SimpleSelector& rhs) const; |
308 | |
309 | ATTACH_CMP_OPERATIONS(ComplexSelector) |
310 | ATTACH_AST_OPERATIONS(ComplexSelector) |
311 | ATTACH_CRTP_PERFORM_METHODS() |
312 | }; |
313 | |
314 | //////////////////////////////////////////////////////////////////////////// |
315 | // Base class for complex selector components |
316 | //////////////////////////////////////////////////////////////////////////// |
317 | class SelectorComponent : public Selector { |
318 | // line break after list separator |
319 | ADD_PROPERTY(bool, hasPostLineBreak) |
320 | public: |
321 | SelectorComponent(SourceSpan pstate, bool postLineBreak = false); |
322 | size_t hash() const override = 0; |
323 | void cloneChildren() override; |
324 | |
325 | |
326 | // By default we consider instances not empty |
327 | virtual bool empty() const { return false; } |
328 | |
329 | virtual bool has_placeholder() const = 0; |
330 | bool has_real_parent_ref() const override = 0; |
331 | |
332 | ComplexSelector* wrapInComplex(); |
333 | |
334 | size_t maxSpecificity() const override { return 0; } |
335 | size_t minSpecificity() const override { return 0; } |
336 | |
337 | virtual bool isCompound() const { return false; }; |
338 | virtual bool isCombinator() const { return false; }; |
339 | |
340 | /* helper function for syntax sugar */ |
341 | virtual CompoundSelector* getCompound() { return NULL; } |
342 | virtual SelectorCombinator* getCombinator() { return NULL; } |
343 | virtual const CompoundSelector* getCompound() const { return NULL; } |
344 | virtual const SelectorCombinator* getCombinator() const { return NULL; } |
345 | |
346 | virtual unsigned long specificity() const override; |
347 | bool operator==(const Selector& rhs) const override = 0; |
348 | ATTACH_VIRTUAL_CMP_OPERATIONS(SelectorComponent); |
349 | ATTACH_VIRTUAL_AST_OPERATIONS(SelectorComponent); |
350 | }; |
351 | |
352 | //////////////////////////////////////////////////////////////////////////// |
353 | // A specific combinator between compound selectors |
354 | //////////////////////////////////////////////////////////////////////////// |
355 | class SelectorCombinator final : public SelectorComponent { |
356 | public: |
357 | |
358 | // Enumerate all possible selector combinators. There is some |
359 | // discrepancy with dart-sass. Opted to name them as in CSS33 |
360 | enum Combinator { CHILD /* > */, GENERAL /* ~ */, ADJACENT /* + */}; |
361 | |
362 | private: |
363 | |
364 | // Store the type of this combinator |
365 | HASH_CONSTREF(Combinator, combinator) |
366 | |
367 | public: |
368 | SelectorCombinator(SourceSpan pstate, Combinator combinator, bool postLineBreak = false); |
369 | |
370 | bool has_real_parent_ref() const override { return false; } |
371 | bool has_placeholder() const override { return false; } |
372 | |
373 | /* helper function for syntax sugar */ |
374 | SelectorCombinator* getCombinator() final override { return this; } |
375 | const SelectorCombinator* getCombinator() const final override { return this; } |
376 | |
377 | // Query type of combinator |
378 | bool isCombinator() const override { return true; }; |
379 | |
380 | // Matches the right-hand selector if it's a direct child of the left- |
381 | // hand selector in the DOM tree. Dart-sass also calls this `child` |
382 | // https://developer.mozilla.org/en-US/docs/Web/CSS/Child_combinator |
383 | bool isChildCombinator() const { return combinator_ == CHILD; } // > |
384 | |
385 | // Matches the right-hand selector if it comes after the left-hand |
386 | // selector in the DOM tree. Dart-sass class this `followingSibling` |
387 | // https://developer.mozilla.org/en-US/docs/Web/CSS/General_sibling_combinator |
388 | bool isGeneralCombinator() const { return combinator_ == GENERAL; } // ~ |
389 | |
390 | // Matches the right-hand selector if it's immediately adjacent to the |
391 | // left-hand selector in the DOM tree. Dart-sass calls this `nextSibling` |
392 | // https://developer.mozilla.org/en-US/docs/Web/CSS/Adjacent_sibling_combinator |
393 | bool isAdjacentCombinator() const { return combinator_ == ADJACENT; } // + |
394 | |
395 | size_t maxSpecificity() const override { return 0; } |
396 | size_t minSpecificity() const override { return 0; } |
397 | |
398 | size_t hash() const override { |
399 | return std::hash<int>()(combinator_); |
400 | } |
401 | void cloneChildren() override; |
402 | virtual unsigned long specificity() const override; |
403 | bool operator==(const Selector& rhs) const override; |
404 | bool operator==(const SelectorComponent& rhs) const override; |
405 | |
406 | ATTACH_CMP_OPERATIONS(SelectorCombinator) |
407 | ATTACH_AST_OPERATIONS(SelectorCombinator) |
408 | ATTACH_CRTP_PERFORM_METHODS() |
409 | }; |
410 | |
411 | //////////////////////////////////////////////////////////////////////////// |
412 | // A compound selector consists of multiple simple selectors |
413 | //////////////////////////////////////////////////////////////////////////// |
414 | class CompoundSelector final : public SelectorComponent, public Vectorized<SimpleSelectorObj> { |
415 | ADD_PROPERTY(bool, hasRealParent) |
416 | ADD_PROPERTY(bool, extended) |
417 | public: |
418 | CompoundSelector(SourceSpan pstate, bool postLineBreak = false); |
419 | |
420 | // Returns true if this compound selector |
421 | // fullfills various criteria. |
422 | bool isInvisible() const; |
423 | |
424 | bool empty() const override { |
425 | return Vectorized::empty(); |
426 | } |
427 | |
428 | size_t hash() const override; |
429 | CompoundSelector* unifyWith(CompoundSelector* rhs); |
430 | |
431 | /* helper function for syntax sugar */ |
432 | CompoundSelector* getCompound() final override { return this; } |
433 | const CompoundSelector* getCompound() const final override { return this; } |
434 | |
435 | bool isSuperselectorOf(const CompoundSelector* sub, sass::string wrapped = "" ) const; |
436 | |
437 | void cloneChildren() override; |
438 | bool has_real_parent_ref() const override; |
439 | bool has_placeholder() const override; |
440 | sass::vector<ComplexSelectorObj> resolve_parent_refs(SelectorStack pstack, Backtraces& traces, bool implicit_parent = true); |
441 | |
442 | virtual bool isCompound() const override { return true; }; |
443 | virtual unsigned long specificity() const override; |
444 | |
445 | size_t maxSpecificity() const override; |
446 | size_t minSpecificity() const override; |
447 | |
448 | bool operator==(const Selector& rhs) const override; |
449 | |
450 | bool operator==(const SelectorComponent& rhs) const override; |
451 | |
452 | bool operator==(const SelectorList& rhs) const; |
453 | bool operator==(const ComplexSelector& rhs) const; |
454 | bool operator==(const SimpleSelector& rhs) const; |
455 | |
456 | void sortChildren(); |
457 | |
458 | ATTACH_CMP_OPERATIONS(CompoundSelector) |
459 | ATTACH_AST_OPERATIONS(CompoundSelector) |
460 | ATTACH_CRTP_PERFORM_METHODS() |
461 | }; |
462 | |
463 | /////////////////////////////////// |
464 | // Comma-separated selector groups. |
465 | /////////////////////////////////// |
466 | class SelectorList final : public Selector, public Vectorized<ComplexSelectorObj> { |
467 | private: |
468 | // maybe we have optional flag |
469 | // ToDo: should be at ExtendRule? |
470 | ADD_PROPERTY(bool, is_optional) |
471 | public: |
472 | SelectorList(SourceSpan pstate, size_t s = 0); |
473 | sass::string type() const override { return "list" ; } |
474 | size_t hash() const override; |
475 | |
476 | SelectorList* unifyWith(SelectorList*); |
477 | |
478 | // Returns true if all complex selectors |
479 | // can have real parents, meaning every |
480 | // first component does allow for it |
481 | bool isInvisible() const; |
482 | |
483 | void cloneChildren() override; |
484 | bool has_real_parent_ref() const override; |
485 | SelectorList* resolve_parent_refs(SelectorStack pstack, Backtraces& traces, bool implicit_parent = true); |
486 | virtual unsigned long specificity() const override; |
487 | |
488 | bool isSuperselectorOf(const SelectorList* sub) const; |
489 | |
490 | size_t maxSpecificity() const override; |
491 | size_t minSpecificity() const override; |
492 | |
493 | bool operator==(const Selector& rhs) const override; |
494 | bool operator==(const ComplexSelector& rhs) const; |
495 | bool operator==(const CompoundSelector& rhs) const; |
496 | bool operator==(const SimpleSelector& rhs) const; |
497 | // Selector Lists can be compared to comma lists |
498 | bool operator==(const Expression& rhs) const override; |
499 | |
500 | ATTACH_CMP_OPERATIONS(SelectorList) |
501 | ATTACH_AST_OPERATIONS(SelectorList) |
502 | ATTACH_CRTP_PERFORM_METHODS() |
503 | }; |
504 | |
505 | //////////////////////////////// |
506 | // The Sass `@extend` directive. |
507 | //////////////////////////////// |
508 | class ExtendRule final : public Statement { |
509 | ADD_PROPERTY(bool, isOptional) |
510 | // This should be a simple selector only! |
511 | ADD_PROPERTY(SelectorListObj, selector) |
512 | ADD_PROPERTY(Selector_Schema_Obj, schema) |
513 | public: |
514 | ExtendRule(SourceSpan pstate, SelectorListObj s); |
515 | ExtendRule(SourceSpan pstate, Selector_Schema_Obj s); |
516 | ATTACH_AST_OPERATIONS(ExtendRule) |
517 | ATTACH_CRTP_PERFORM_METHODS() |
518 | }; |
519 | |
520 | } |
521 | |
522 | #endif |
523 | |