Skip to content
This repository was archived by the owner on Oct 24, 2025. It is now read-only.

Commit ac4e48b

Browse files
committed
Move string functions to own compile unit
1 parent 37cfb4c commit ac4e48b

File tree

8 files changed

+303
-263
lines changed

8 files changed

+303
-263
lines changed

Makefile.conf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ SOURCES = \
1313
fn_utils.cpp \
1414
fn_colors.cpp \
1515
fn_numbers.cpp \
16+
fn_strings.cpp \
1617
fn_selectors.cpp \
1718
functions.cpp \
1819
color_maps.cpp \

src/context.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include "fn_utils.hpp"
3333
#include "fn_colors.hpp"
3434
#include "fn_numbers.hpp"
35+
#include "fn_strings.hpp"
3536
#include "fn_selectors.hpp"
3637

3738
namespace Sass {

src/fn_strings.cpp

Lines changed: 258 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
1+
#include "ast.hpp"
2+
#include "fn_utils.hpp"
3+
#include "fn_strings.hpp"
4+
5+
namespace Sass {
6+
7+
namespace Functions {
8+
9+
void handle_utf8_error (const ParserState& pstate, Backtraces traces)
10+
{
11+
try {
12+
throw;
13+
}
14+
catch (utf8::invalid_code_point) {
15+
std::string msg("utf8::invalid_code_point");
16+
error(msg, pstate, traces);
17+
}
18+
catch (utf8::not_enough_room) {
19+
std::string msg("utf8::not_enough_room");
20+
error(msg, pstate, traces);
21+
}
22+
catch (utf8::invalid_utf8) {
23+
std::string msg("utf8::invalid_utf8");
24+
error(msg, pstate, traces);
25+
}
26+
catch (...) { throw; }
27+
}
28+
29+
///////////////////
30+
// STRING FUNCTIONS
31+
///////////////////
32+
33+
Signature unquote_sig = "unquote($string)";
34+
BUILT_IN(sass_unquote)
35+
{
36+
AST_Node_Obj arg = env["$string"];
37+
if (String_Quoted_Ptr string_quoted = Cast<String_Quoted>(arg)) {
38+
String_Constant_Ptr result = SASS_MEMORY_NEW(String_Constant, pstate, string_quoted->value());
39+
// remember if the string was quoted (color tokens)
40+
result->is_delayed(true); // delay colors
41+
return result;
42+
}
43+
else if (String_Constant_Ptr str = Cast<String_Constant>(arg)) {
44+
return str;
45+
}
46+
else if (Value_Ptr ex = Cast<Value>(arg)) {
47+
Sass_Output_Style oldstyle = ctx.c_options.output_style;
48+
ctx.c_options.output_style = SASS_STYLE_NESTED;
49+
std::string val(arg->to_string(ctx.c_options));
50+
val = Cast<Null>(arg) ? "null" : val;
51+
ctx.c_options.output_style = oldstyle;
52+
53+
deprecated_function("Passing " + val + ", a non-string value, to unquote()", pstate);
54+
return ex;
55+
}
56+
throw std::runtime_error("Invalid Data Type for unquote");
57+
}
58+
59+
Signature quote_sig = "quote($string)";
60+
BUILT_IN(sass_quote)
61+
{
62+
AST_Node_Obj arg = env["$string"];
63+
// only set quote mark to true if already a string
64+
if (String_Quoted_Ptr qstr = Cast<String_Quoted>(arg)) {
65+
qstr->quote_mark('*');
66+
return qstr;
67+
}
68+
// all other nodes must be converted to a string node
69+
std::string str(quote(arg->to_string(ctx.c_options), String_Constant::double_quote()));
70+
String_Quoted_Ptr result = SASS_MEMORY_NEW(String_Quoted, pstate, str);
71+
result->quote_mark('*');
72+
return result;
73+
}
74+
75+
76+
Signature str_length_sig = "str-length($string)";
77+
BUILT_IN(str_length)
78+
{
79+
size_t len = std::string::npos;
80+
try {
81+
String_Constant_Ptr s = ARG("$string", String_Constant);
82+
len = UTF_8::code_point_count(s->value(), 0, s->value().size());
83+
84+
}
85+
// handle any invalid utf8 errors
86+
// other errors will be re-thrown
87+
catch (...) { handle_utf8_error(pstate, traces); }
88+
// return something even if we had an error (-1)
89+
return SASS_MEMORY_NEW(Number, pstate, (double)len);
90+
}
91+
92+
Signature str_insert_sig = "str-insert($string, $insert, $index)";
93+
BUILT_IN(str_insert)
94+
{
95+
std::string str;
96+
try {
97+
String_Constant_Ptr s = ARG("$string", String_Constant);
98+
str = s->value();
99+
str = unquote(str);
100+
String_Constant_Ptr i = ARG("$insert", String_Constant);
101+
std::string ins = i->value();
102+
ins = unquote(ins);
103+
double index = ARGVAL("$index");
104+
size_t len = UTF_8::code_point_count(str, 0, str.size());
105+
106+
if (index > 0 && index <= len) {
107+
// positive and within string length
108+
str.insert(UTF_8::offset_at_position(str, static_cast<size_t>(index) - 1), ins);
109+
}
110+
else if (index > len) {
111+
// positive and past string length
112+
str += ins;
113+
}
114+
else if (index == 0) {
115+
str = ins + str;
116+
}
117+
else if (std::abs(index) <= len) {
118+
// negative and within string length
119+
index += len + 1;
120+
str.insert(UTF_8::offset_at_position(str, static_cast<size_t>(index)), ins);
121+
}
122+
else {
123+
// negative and past string length
124+
str = ins + str;
125+
}
126+
127+
if (String_Quoted_Ptr ss = Cast<String_Quoted>(s)) {
128+
if (ss->quote_mark()) str = quote(str);
129+
}
130+
}
131+
// handle any invalid utf8 errors
132+
// other errors will be re-thrown
133+
catch (...) { handle_utf8_error(pstate, traces); }
134+
return SASS_MEMORY_NEW(String_Quoted, pstate, str);
135+
}
136+
137+
Signature str_index_sig = "str-index($string, $substring)";
138+
BUILT_IN(str_index)
139+
{
140+
size_t index = std::string::npos;
141+
try {
142+
String_Constant_Ptr s = ARG("$string", String_Constant);
143+
String_Constant_Ptr t = ARG("$substring", String_Constant);
144+
std::string str = s->value();
145+
str = unquote(str);
146+
std::string substr = t->value();
147+
substr = unquote(substr);
148+
149+
size_t c_index = str.find(substr);
150+
if(c_index == std::string::npos) {
151+
return SASS_MEMORY_NEW(Null, pstate);
152+
}
153+
index = UTF_8::code_point_count(str, 0, c_index) + 1;
154+
}
155+
// handle any invalid utf8 errors
156+
// other errors will be re-thrown
157+
catch (...) { handle_utf8_error(pstate, traces); }
158+
// return something even if we had an error (-1)
159+
return SASS_MEMORY_NEW(Number, pstate, (double)index);
160+
}
161+
162+
Signature str_slice_sig = "str-slice($string, $start-at, $end-at:-1)";
163+
BUILT_IN(str_slice)
164+
{
165+
std::string newstr;
166+
try {
167+
String_Constant_Ptr s = ARG("$string", String_Constant);
168+
double start_at = ARGVAL("$start-at");
169+
double end_at = ARGVAL("$end-at");
170+
String_Quoted_Ptr ss = Cast<String_Quoted>(s);
171+
172+
std::string str = unquote(s->value());
173+
174+
size_t size = utf8::distance(str.begin(), str.end());
175+
176+
if (!Cast<Number>(env["$end-at"])) {
177+
end_at = -1;
178+
}
179+
180+
if (end_at == 0 || (end_at + size) < 0) {
181+
if (ss && ss->quote_mark()) newstr = quote("");
182+
return SASS_MEMORY_NEW(String_Quoted, pstate, newstr);
183+
}
184+
185+
if (end_at < 0) {
186+
end_at += size + 1;
187+
if (end_at == 0) end_at = 1;
188+
}
189+
if (end_at > size) { end_at = (double)size; }
190+
if (start_at < 0) {
191+
start_at += size + 1;
192+
if (start_at < 0) start_at = 0;
193+
}
194+
else if (start_at == 0) { ++ start_at; }
195+
196+
if (start_at <= end_at)
197+
{
198+
std::string::iterator start = str.begin();
199+
utf8::advance(start, start_at - 1, str.end());
200+
std::string::iterator end = start;
201+
utf8::advance(end, end_at - start_at + 1, str.end());
202+
newstr = std::string(start, end);
203+
}
204+
if (ss) {
205+
if(ss->quote_mark()) newstr = quote(newstr);
206+
}
207+
}
208+
// handle any invalid utf8 errors
209+
// other errors will be re-thrown
210+
catch (...) { handle_utf8_error(pstate, traces); }
211+
return SASS_MEMORY_NEW(String_Quoted, pstate, newstr);
212+
}
213+
214+
Signature to_upper_case_sig = "to-upper-case($string)";
215+
BUILT_IN(to_upper_case)
216+
{
217+
String_Constant_Ptr s = ARG("$string", String_Constant);
218+
std::string str = s->value();
219+
220+
for (size_t i = 0, L = str.length(); i < L; ++i) {
221+
if (Sass::Util::isAscii(str[i])) {
222+
str[i] = std::toupper(str[i]);
223+
}
224+
}
225+
226+
if (String_Quoted_Ptr ss = Cast<String_Quoted>(s)) {
227+
String_Quoted_Ptr cpy = SASS_MEMORY_COPY(ss);
228+
cpy->value(str);
229+
return cpy;
230+
} else {
231+
return SASS_MEMORY_NEW(String_Quoted, pstate, str);
232+
}
233+
}
234+
235+
Signature to_lower_case_sig = "to-lower-case($string)";
236+
BUILT_IN(to_lower_case)
237+
{
238+
String_Constant_Ptr s = ARG("$string", String_Constant);
239+
std::string str = s->value();
240+
241+
for (size_t i = 0, L = str.length(); i < L; ++i) {
242+
if (Sass::Util::isAscii(str[i])) {
243+
str[i] = std::tolower(str[i]);
244+
}
245+
}
246+
247+
if (String_Quoted_Ptr ss = Cast<String_Quoted>(s)) {
248+
String_Quoted_Ptr cpy = SASS_MEMORY_COPY(ss);
249+
cpy->value(str);
250+
return cpy;
251+
} else {
252+
return SASS_MEMORY_NEW(String_Quoted, pstate, str);
253+
}
254+
}
255+
256+
}
257+
258+
}

src/fn_strings.hpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#ifndef SASS_FN_STRINGS_H
2+
#define SASS_FN_STRINGS_H
3+
4+
#include "fn_utils.hpp"
5+
6+
namespace Sass {
7+
8+
namespace Functions {
9+
10+
extern Signature unquote_sig;
11+
extern Signature quote_sig;
12+
extern Signature str_length_sig;
13+
extern Signature str_insert_sig;
14+
extern Signature str_index_sig;
15+
extern Signature str_slice_sig;
16+
extern Signature to_upper_case_sig;
17+
extern Signature to_lower_case_sig;
18+
extern Signature length_sig;
19+
20+
BUILT_IN(sass_unquote);
21+
BUILT_IN(sass_quote);
22+
BUILT_IN(str_length);
23+
BUILT_IN(str_insert);
24+
BUILT_IN(str_index);
25+
BUILT_IN(str_slice);
26+
BUILT_IN(to_upper_case);
27+
BUILT_IN(to_lower_case);
28+
BUILT_IN(length);
29+
30+
}
31+
32+
}
33+
34+
#endif

0 commit comments

Comments
 (0)