Skip to content

Commit 4d1e036

Browse files
committed
Move list functions to own compile unit
1 parent ac4e48b commit 4d1e036

File tree

8 files changed

+329
-292
lines changed

8 files changed

+329
-292
lines changed

Makefile.conf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ SOURCES = \
1111
context.cpp \
1212
constants.cpp \
1313
fn_utils.cpp \
14+
fn_lists.cpp \
1415
fn_colors.cpp \
1516
fn_numbers.cpp \
1617
fn_strings.cpp \

src/context.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "prelexer.hpp"
3131
#include "emitter.hpp"
3232
#include "fn_utils.hpp"
33+
#include "fn_lists.hpp"
3334
#include "fn_colors.hpp"
3435
#include "fn_numbers.hpp"
3536
#include "fn_strings.hpp"

src/fn_lists.cpp

Lines changed: 284 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,284 @@
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+
}

src/fn_lists.hpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#ifndef SASS_FN_LISTS_H
2+
#define SASS_FN_LISTS_H
3+
4+
#include "fn_utils.hpp"
5+
6+
namespace Sass {
7+
8+
namespace Functions {
9+
10+
extern Signature length_sig;
11+
extern Signature nth_sig;
12+
extern Signature index_sig;
13+
extern Signature join_sig;
14+
extern Signature append_sig;
15+
extern Signature zip_sig;
16+
extern Signature list_separator_sig;
17+
extern Signature is_bracketed_sig;
18+
extern Signature keywords_sig;
19+
20+
BUILT_IN(length);
21+
BUILT_IN(nth);
22+
BUILT_IN(index);
23+
BUILT_IN(join);
24+
BUILT_IN(append);
25+
BUILT_IN(zip);
26+
BUILT_IN(list_separator);
27+
BUILT_IN(is_bracketed);
28+
BUILT_IN(keywords);
29+
30+
}
31+
32+
}
33+
34+
#endif

0 commit comments

Comments
 (0)