1+ #include " parser.hpp"
2+ #include " extend.hpp"
3+ #include " fn_utils.hpp"
4+ #include " fn_selectors.hpp"
5+
6+ namespace Sass {
7+
8+ namespace Functions {
9+
10+ Signature selector_nest_sig = " selector-nest($selectors...)" ;
11+ BUILT_IN (selector_nest)
12+ {
13+ List_Ptr arglist = ARG (" $selectors" , List);
14+
15+ // Not enough parameters
16+ if ( arglist->length () == 0 )
17+ error (" $selectors: At least one selector must be passed for `selector-nest'" , pstate, traces);
18+
19+ // Parse args into vector of selectors
20+ SelectorStack parsedSelectors;
21+ for (size_t i = 0 , L = arglist->length (); i < L; ++i) {
22+ Expression_Obj exp = Cast<Expression>(arglist->value_at_index (i));
23+ if (exp->concrete_type () == Expression::NULL_VAL) {
24+ std::stringstream msg;
25+ msg << " $selectors: null is not a valid selector: it must be a string,\n " ;
26+ msg << " a list of strings, or a list of lists of strings for 'selector-nest'" ;
27+ error (msg.str (), pstate, traces);
28+ }
29+ if (String_Constant_Obj str = Cast<String_Constant>(exp)) {
30+ str->quote_mark (0 );
31+ }
32+ std::string exp_src = exp->to_string (ctx.c_options );
33+ Selector_List_Obj sel = Parser::parse_selector (exp_src.c_str (), ctx, traces);
34+ parsedSelectors.push_back (sel);
35+ }
36+
37+ // Nothing to do
38+ if ( parsedSelectors.empty () ) {
39+ return SASS_MEMORY_NEW (Null, pstate);
40+ }
41+
42+ // Set the first element as the `result`, keep appending to as we go down the parsedSelector vector.
43+ SelectorStack::iterator itr = parsedSelectors.begin ();
44+ Selector_List_Obj result = *itr;
45+ ++itr;
46+
47+ for (;itr != parsedSelectors.end (); ++itr) {
48+ Selector_List_Obj child = *itr;
49+ std::vector<Complex_Selector_Obj> exploded;
50+ selector_stack.push_back (result);
51+ Selector_List_Obj rv = child->resolve_parent_refs (selector_stack, traces);
52+ selector_stack.pop_back ();
53+ for (size_t m = 0 , mLen = rv->length (); m < mLen ; ++m) {
54+ exploded.push_back ((*rv)[m]);
55+ }
56+ result->elements (exploded);
57+ }
58+
59+ Listize listize;
60+ return Cast<Value>(result->perform (&listize));
61+ }
62+
63+ Signature selector_append_sig = " selector-append($selectors...)" ;
64+ BUILT_IN (selector_append)
65+ {
66+ List_Ptr arglist = ARG (" $selectors" , List);
67+
68+ // Not enough parameters
69+ if ( arglist->length () == 0 )
70+ error (" $selectors: At least one selector must be passed for `selector-append'" , pstate, traces);
71+
72+ // Parse args into vector of selectors
73+ SelectorStack parsedSelectors;
74+ for (size_t i = 0 , L = arglist->length (); i < L; ++i) {
75+ Expression_Obj exp = Cast<Expression>(arglist->value_at_index (i));
76+ if (exp->concrete_type () == Expression::NULL_VAL) {
77+ std::stringstream msg;
78+ msg << " $selectors: null is not a valid selector: it must be a string,\n " ;
79+ msg << " a list of strings, or a list of lists of strings for 'selector-append'" ;
80+ error (msg.str (), pstate, traces);
81+ }
82+ if (String_Constant_Ptr str = Cast<String_Constant>(exp)) {
83+ str->quote_mark (0 );
84+ }
85+ std::string exp_src = exp->to_string ();
86+ Selector_List_Obj sel = Parser::parse_selector (exp_src.c_str (), ctx, traces);
87+ parsedSelectors.push_back (sel);
88+ }
89+
90+ // Nothing to do
91+ if ( parsedSelectors.empty () ) {
92+ return SASS_MEMORY_NEW (Null, pstate);
93+ }
94+
95+ // Set the first element as the `result`, keep appending to as we go down the parsedSelector vector.
96+ SelectorStack::iterator itr = parsedSelectors.begin ();
97+ Selector_List_Obj result = *itr;
98+ ++itr;
99+
100+ for (;itr != parsedSelectors.end (); ++itr) {
101+ Selector_List_Obj child = *itr;
102+ std::vector<Complex_Selector_Obj> newElements;
103+
104+ // For every COMPLEX_SELECTOR in `result`
105+ // For every COMPLEX_SELECTOR in `child`
106+ // let parentSeqClone equal a copy of result->elements[i]
107+ // let childSeq equal child->elements[j]
108+ // Append all of childSeq head elements into parentSeqClone
109+ // Set the innermost tail of parentSeqClone, to childSeq's tail
110+ // Replace result->elements with newElements
111+ for (size_t i = 0 , resultLen = result->length (); i < resultLen; ++i) {
112+ for (size_t j = 0 , childLen = child->length (); j < childLen; ++j) {
113+ Complex_Selector_Obj parentSeqClone = SASS_MEMORY_CLONE ((*result)[i]);
114+ Complex_Selector_Obj childSeq = (*child)[j];
115+ Complex_Selector_Obj base = childSeq->tail ();
116+
117+ // Must be a simple sequence
118+ if ( childSeq->combinator () != Complex_Selector::Combinator::ANCESTOR_OF ) {
119+ std::string msg (" Can't append \" " );
120+ msg += childSeq->to_string ();
121+ msg += " \" to \" " ;
122+ msg += parentSeqClone->to_string ();
123+ msg += " \" for `selector-append'" ;
124+ error (msg, pstate, traces);
125+ }
126+
127+ // Cannot be a Universal selector
128+ Element_Selector_Obj pType = Cast<Element_Selector>(childSeq->head ()->first ());
129+ if (pType && pType->name () == " *" ) {
130+ std::string msg (" Can't append \" " );
131+ msg += childSeq->to_string ();
132+ msg += " \" to \" " ;
133+ msg += parentSeqClone->to_string ();
134+ msg += " \" for `selector-append'" ;
135+ error (msg, pstate, traces);
136+ }
137+
138+ // TODO: Add check for namespace stuff
139+
140+ // append any selectors in childSeq's head
141+ parentSeqClone->innermost ()->head ()->concat (base->head ());
142+
143+ // Set parentSeqClone new tail
144+ parentSeqClone->innermost ()->tail ( base->tail () );
145+
146+ newElements.push_back (parentSeqClone);
147+ }
148+ }
149+
150+ result->elements (newElements);
151+ }
152+
153+ Listize listize;
154+ return Cast<Value>(result->perform (&listize));
155+ }
156+
157+ Signature selector_unify_sig = " selector-unify($selector1, $selector2)" ;
158+ BUILT_IN (selector_unify)
159+ {
160+ Selector_List_Obj selector1 = ARGSELS (" $selector1" );
161+ Selector_List_Obj selector2 = ARGSELS (" $selector2" );
162+
163+ Selector_List_Obj result = selector1->unify_with (selector2);
164+ Listize listize;
165+ return Cast<Value>(result->perform (&listize));
166+ }
167+
168+ Signature simple_selectors_sig = " simple-selectors($selector)" ;
169+ BUILT_IN (simple_selectors)
170+ {
171+ Compound_Selector_Obj sel = ARGSEL (" $selector" );
172+
173+ List_Ptr l = SASS_MEMORY_NEW (List, sel->pstate (), sel->length (), SASS_COMMA);
174+
175+ for (size_t i = 0 , L = sel->length (); i < L; ++i) {
176+ Simple_Selector_Obj ss = (*sel)[i];
177+ std::string ss_string = ss->to_string () ;
178+
179+ l->append (SASS_MEMORY_NEW (String_Quoted, ss->pstate (), ss_string));
180+ }
181+
182+ return l;
183+ }
184+
185+ Signature selector_extend_sig = " selector-extend($selector, $extendee, $extender)" ;
186+ BUILT_IN (selector_extend)
187+ {
188+ Selector_List_Obj selector = ARGSELS (" $selector" );
189+ Selector_List_Obj extendee = ARGSELS (" $extendee" );
190+ Selector_List_Obj extender = ARGSELS (" $extender" );
191+
192+ Subset_Map subset_map;
193+ extender->populate_extends (extendee, subset_map);
194+ Extend extend (subset_map);
195+
196+ Selector_List_Obj result = extend.extendSelectorList (selector, false );
197+
198+ Listize listize;
199+ return Cast<Value>(result->perform (&listize));
200+ }
201+
202+ Signature selector_replace_sig = " selector-replace($selector, $original, $replacement)" ;
203+ BUILT_IN (selector_replace)
204+ {
205+ Selector_List_Obj selector = ARGSELS (" $selector" );
206+ Selector_List_Obj original = ARGSELS (" $original" );
207+ Selector_List_Obj replacement = ARGSELS (" $replacement" );
208+ Subset_Map subset_map;
209+ replacement->populate_extends (original, subset_map);
210+ Extend extend (subset_map);
211+
212+ Selector_List_Obj result = extend.extendSelectorList (selector, true );
213+
214+ Listize listize;
215+ return Cast<Value>(result->perform (&listize));
216+ }
217+
218+ Signature selector_parse_sig = " selector-parse($selector)" ;
219+ BUILT_IN (selector_parse)
220+ {
221+ Selector_List_Obj sel = ARGSELS (" $selector" );
222+
223+ Listize listize;
224+ return Cast<Value>(sel->perform (&listize));
225+ }
226+
227+ Signature is_superselector_sig = " is-superselector($super, $sub)" ;
228+ BUILT_IN (is_superselector)
229+ {
230+ Selector_List_Obj sel_sup = ARGSELS (" $super" );
231+ Selector_List_Obj sel_sub = ARGSELS (" $sub" );
232+ bool result = sel_sup->is_superselector_of (sel_sub);
233+ return SASS_MEMORY_NEW (Boolean, pstate, result);
234+ }
235+
236+ }
237+
238+ }
0 commit comments