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

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