1
+ #include " listize.hpp"
2
+ #include " operators.hpp"
3
+ #include " fn_utils.hpp"
4
+ #include " fn_lists.hpp"
5
+
6
+ namespace Sass {
7
+
8
+ namespace Functions {
9
+
10
+ // ///////////////
11
+ // LIST FUNCTIONS
12
+ // ///////////////
13
+
14
+ Signature keywords_sig = " keywords($args)" ;
15
+ BUILT_IN (keywords)
16
+ {
17
+ List_Obj arglist = SASS_MEMORY_COPY (ARG (" $args" , List)); // copy
18
+ Map_Obj result = SASS_MEMORY_NEW (Map, pstate, 1 );
19
+ for (size_t i = arglist->size (), L = arglist->length (); i < L; ++i) {
20
+ Expression_Obj obj = arglist->at (i);
21
+ Argument_Obj arg = (Argument_Ptr) obj.ptr (); // XXX
22
+ std::string name = std::string (arg->name ());
23
+ name = name.erase (0 , 1 ); // sanitize name (remove dollar sign)
24
+ *result << std::make_pair (SASS_MEMORY_NEW (String_Quoted,
25
+ pstate, name),
26
+ arg->value ());
27
+ }
28
+ return result.detach ();
29
+ }
30
+
31
+ Signature length_sig = " length($list)" ;
32
+ BUILT_IN (length)
33
+ {
34
+ if (Selector_List_Ptr sl = Cast<Selector_List>(env[" $list" ])) {
35
+ return SASS_MEMORY_NEW (Number, pstate, (double )sl->length ());
36
+ }
37
+ Expression_Ptr v = ARG (" $list" , Expression);
38
+ if (v->concrete_type () == Expression::MAP) {
39
+ Map_Ptr map = Cast<Map>(env[" $list" ]);
40
+ return SASS_MEMORY_NEW (Number, pstate, (double )(map ? map->length () : 1 ));
41
+ }
42
+ if (v->concrete_type () == Expression::SELECTOR) {
43
+ if (Compound_Selector_Ptr h = Cast<Compound_Selector>(v)) {
44
+ return SASS_MEMORY_NEW (Number, pstate, (double )h->length ());
45
+ } else if (Selector_List_Ptr ls = Cast<Selector_List>(v)) {
46
+ return SASS_MEMORY_NEW (Number, pstate, (double )ls->length ());
47
+ } else {
48
+ return SASS_MEMORY_NEW (Number, pstate, 1 );
49
+ }
50
+ }
51
+
52
+ List_Ptr list = Cast<List>(env[" $list" ]);
53
+ return SASS_MEMORY_NEW (Number,
54
+ pstate,
55
+ (double )(list ? list->size () : 1 ));
56
+ }
57
+
58
+ Signature nth_sig = " nth($list, $n)" ;
59
+ BUILT_IN (nth)
60
+ {
61
+ double nr = ARGVAL (" $n" );
62
+ Map_Ptr m = Cast<Map>(env[" $list" ]);
63
+ if (Selector_List_Ptr sl = Cast<Selector_List>(env[" $list" ])) {
64
+ size_t len = m ? m->length () : sl->length ();
65
+ bool empty = m ? m->empty () : sl->empty ();
66
+ if (empty) error (" argument `$list` of `" + std::string (sig) + " ` must not be empty" , pstate, traces);
67
+ double index = std::floor (nr < 0 ? len + nr : nr - 1 );
68
+ if (index < 0 || index > len - 1 ) error (" index out of bounds for `" + std::string (sig) + " `" , pstate, traces);
69
+ // return (*sl)[static_cast<int>(index)];
70
+ Listize listize;
71
+ return Cast<Value>((*sl)[static_cast <int >(index)]->perform (&listize));
72
+ }
73
+ List_Obj l = Cast<List>(env[" $list" ]);
74
+ if (nr == 0 ) error (" argument `$n` of `" + std::string (sig) + " ` must be non-zero" , pstate, traces);
75
+ // if the argument isn't a list, then wrap it in a singleton list
76
+ if (!m && !l) {
77
+ l = SASS_MEMORY_NEW (List, pstate, 1 );
78
+ l->append (ARG (" $list" , Expression));
79
+ }
80
+ size_t len = m ? m->length () : l->length ();
81
+ bool empty = m ? m->empty () : l->empty ();
82
+ if (empty) error (" argument `$list` of `" + std::string (sig) + " ` must not be empty" , pstate, traces);
83
+ double index = std::floor (nr < 0 ? len + nr : nr - 1 );
84
+ if (index < 0 || index > len - 1 ) error (" index out of bounds for `" + std::string (sig) + " `" , pstate, traces);
85
+
86
+ if (m) {
87
+ l = SASS_MEMORY_NEW (List, pstate, 1 );
88
+ l->append (m->keys ()[static_cast <unsigned int >(index)]);
89
+ l->append (m->at (m->keys ()[static_cast <unsigned int >(index)]));
90
+ return l.detach ();
91
+ }
92
+ else {
93
+ Value_Obj rv = l->value_at_index (static_cast <int >(index));
94
+ rv->set_delayed (false );
95
+ return rv.detach ();
96
+ }
97
+ }
98
+
99
+ Signature set_nth_sig = " set-nth($list, $n, $value)" ;
100
+ BUILT_IN (set_nth)
101
+ {
102
+ Map_Obj m = Cast<Map>(env[" $list" ]);
103
+ List_Obj l = Cast<List>(env[" $list" ]);
104
+ Number_Obj n = ARG (" $n" , Number);
105
+ Expression_Obj v = ARG (" $value" , Expression);
106
+ if (!l) {
107
+ l = SASS_MEMORY_NEW (List, pstate, 1 );
108
+ l->append (ARG (" $list" , Expression));
109
+ }
110
+ if (m) {
111
+ l = m->to_list (pstate);
112
+ }
113
+ if (l->empty ()) error (" argument `$list` of `" + std::string (sig) + " ` must not be empty" , pstate, traces);
114
+ double index = std::floor (n->value () < 0 ? l->length () + n->value () : n->value () - 1 );
115
+ if (index < 0 || index > l->length () - 1 ) error (" index out of bounds for `" + std::string (sig) + " `" , pstate, traces);
116
+ List_Ptr result = SASS_MEMORY_NEW (List, pstate, l->length (), l->separator (), false , l->is_bracketed ());
117
+ for (size_t i = 0 , L = l->length (); i < L; ++i) {
118
+ result->append (((i == index) ? v : (*l)[i]));
119
+ }
120
+ return result;
121
+ }
122
+
123
+ Signature index_sig = " index($list, $value)" ;
124
+ BUILT_IN (index)
125
+ {
126
+ Map_Obj m = Cast<Map>(env[" $list" ]);
127
+ List_Obj l = Cast<List>(env[" $list" ]);
128
+ Expression_Obj v = ARG (" $value" , Expression);
129
+ if (!l) {
130
+ l = SASS_MEMORY_NEW (List, pstate, 1 );
131
+ l->append (ARG (" $list" , Expression));
132
+ }
133
+ if (m) {
134
+ l = m->to_list (pstate);
135
+ }
136
+ for (size_t i = 0 , L = l->length (); i < L; ++i) {
137
+ if (Operators::eq (l->value_at_index (i), v)) return SASS_MEMORY_NEW (Number, pstate, (double )(i+1 ));
138
+ }
139
+ return SASS_MEMORY_NEW (Null, pstate);
140
+ }
141
+
142
+ Signature join_sig = " join($list1, $list2, $separator: auto, $bracketed: auto)" ;
143
+ BUILT_IN (join)
144
+ {
145
+ Map_Obj m1 = Cast<Map>(env[" $list1" ]);
146
+ Map_Obj m2 = Cast<Map>(env[" $list2" ]);
147
+ List_Obj l1 = Cast<List>(env[" $list1" ]);
148
+ List_Obj l2 = Cast<List>(env[" $list2" ]);
149
+ String_Constant_Obj sep = ARG (" $separator" , String_Constant);
150
+ enum Sass_Separator sep_val = (l1 ? l1->separator () : SASS_SPACE);
151
+ Value* bracketed = ARG (" $bracketed" , Value);
152
+ bool is_bracketed = (l1 ? l1->is_bracketed () : false );
153
+ if (!l1) {
154
+ l1 = SASS_MEMORY_NEW (List, pstate, 1 );
155
+ l1->append (ARG (" $list1" , Expression));
156
+ sep_val = (l2 ? l2->separator () : SASS_SPACE);
157
+ is_bracketed = (l2 ? l2->is_bracketed () : false );
158
+ }
159
+ if (!l2) {
160
+ l2 = SASS_MEMORY_NEW (List, pstate, 1 );
161
+ l2->append (ARG (" $list2" , Expression));
162
+ }
163
+ if (m1) {
164
+ l1 = m1->to_list (pstate);
165
+ sep_val = SASS_COMMA;
166
+ }
167
+ if (m2) {
168
+ l2 = m2->to_list (pstate);
169
+ }
170
+ size_t len = l1->length () + l2->length ();
171
+ std::string sep_str = unquote (sep->value ());
172
+ if (sep_str == " space" ) sep_val = SASS_SPACE;
173
+ else if (sep_str == " comma" ) sep_val = SASS_COMMA;
174
+ else if (sep_str != " auto" ) error (" argument `$separator` of `" + std::string (sig) + " ` must be `space`, `comma`, or `auto`" , pstate, traces);
175
+ String_Constant_Obj bracketed_as_str = Cast<String_Constant>(bracketed);
176
+ bool bracketed_is_auto = bracketed_as_str && unquote (bracketed_as_str->value ()) == " auto" ;
177
+ if (!bracketed_is_auto) {
178
+ is_bracketed = !bracketed->is_false ();
179
+ }
180
+ List_Obj result = SASS_MEMORY_NEW (List, pstate, len, sep_val, false , is_bracketed);
181
+ result->concat (l1);
182
+ result->concat (l2);
183
+ return result.detach ();
184
+ }
185
+
186
+ Signature append_sig = " append($list, $val, $separator: auto)" ;
187
+ BUILT_IN (append)
188
+ {
189
+ Map_Obj m = Cast<Map>(env[" $list" ]);
190
+ List_Obj l = Cast<List>(env[" $list" ]);
191
+ Expression_Obj v = ARG (" $val" , Expression);
192
+ if (Selector_List_Ptr sl = Cast<Selector_List>(env[" $list" ])) {
193
+ Listize listize;
194
+ l = Cast<List>(sl->perform (&listize));
195
+ }
196
+ String_Constant_Obj sep = ARG (" $separator" , String_Constant);
197
+ if (!l) {
198
+ l = SASS_MEMORY_NEW (List, pstate, 1 );
199
+ l->append (ARG (" $list" , Expression));
200
+ }
201
+ if (m) {
202
+ l = m->to_list (pstate);
203
+ }
204
+ List_Ptr result = SASS_MEMORY_COPY (l);
205
+ std::string sep_str (unquote (sep->value ()));
206
+ if (sep_str != " auto" ) { // check default first
207
+ if (sep_str == " space" ) result->separator (SASS_SPACE);
208
+ else if (sep_str == " comma" ) result->separator (SASS_COMMA);
209
+ else error (" argument `$separator` of `" + std::string (sig) + " ` must be `space`, `comma`, or `auto`" , pstate, traces);
210
+ }
211
+ if (l->is_arglist ()) {
212
+ result->append (SASS_MEMORY_NEW (Argument,
213
+ v->pstate (),
214
+ v,
215
+ " " ,
216
+ false ,
217
+ false ));
218
+
219
+ } else {
220
+ result->append (v);
221
+ }
222
+ return result;
223
+ }
224
+
225
+ Signature zip_sig = " zip($lists...)" ;
226
+ BUILT_IN (zip)
227
+ {
228
+ List_Obj arglist = SASS_MEMORY_COPY (ARG (" $lists" , List));
229
+ size_t shortest = 0 ;
230
+ for (size_t i = 0 , L = arglist->length (); i < L; ++i) {
231
+ List_Obj ith = Cast<List>(arglist->value_at_index (i));
232
+ Map_Obj mith = Cast<Map>(arglist->value_at_index (i));
233
+ if (!ith) {
234
+ if (mith) {
235
+ ith = mith->to_list (pstate);
236
+ } else {
237
+ ith = SASS_MEMORY_NEW (List, pstate, 1 );
238
+ ith->append (arglist->value_at_index (i));
239
+ }
240
+ if (arglist->is_arglist ()) {
241
+ Argument_Obj arg = (Argument_Ptr)(arglist->at (i).ptr ()); // XXX
242
+ arg->value (ith);
243
+ } else {
244
+ (*arglist)[i] = ith;
245
+ }
246
+ }
247
+ shortest = (i ? std::min (shortest, ith->length ()) : ith->length ());
248
+ }
249
+ List_Ptr zippers = SASS_MEMORY_NEW (List, pstate, shortest, SASS_COMMA);
250
+ size_t L = arglist->length ();
251
+ for (size_t i = 0 ; i < shortest; ++i) {
252
+ List_Ptr zipper = SASS_MEMORY_NEW (List, pstate, L);
253
+ for (size_t j = 0 ; j < L; ++j) {
254
+ zipper->append (Cast<List>(arglist->value_at_index (j))->at (i));
255
+ }
256
+ zippers->append (zipper);
257
+ }
258
+ return zippers;
259
+ }
260
+
261
+ Signature list_separator_sig = " list_separator($list)" ;
262
+ BUILT_IN (list_separator)
263
+ {
264
+ List_Obj l = Cast<List>(env[" $list" ]);
265
+ if (!l) {
266
+ l = SASS_MEMORY_NEW (List, pstate, 1 );
267
+ l->append (ARG (" $list" , Expression));
268
+ }
269
+ return SASS_MEMORY_NEW (String_Quoted,
270
+ pstate,
271
+ l->separator () == SASS_COMMA ? " comma" : " space" );
272
+ }
273
+
274
+ Signature is_bracketed_sig = " is-bracketed($list)" ;
275
+ BUILT_IN (is_bracketed)
276
+ {
277
+ Value_Obj value = ARG (" $list" , Value);
278
+ List_Obj list = Cast<List>(value);
279
+ return SASS_MEMORY_NEW (Boolean, pstate, list && list->is_bracketed ());
280
+ }
281
+
282
+ }
283
+
284
+ }
0 commit comments