Skip to content

Commit 34059f0

Browse files
committed
Implement full rga overloads
1 parent 661a51e commit 34059f0

File tree

3 files changed

+152
-133
lines changed

3 files changed

+152
-133
lines changed

src/context.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -781,7 +781,11 @@ namespace Sass {
781781
{
782782
using namespace Functions;
783783
// RGB Functions
784-
register_function(ctx, rgb_sig, rgb, env);
784+
register_overload_stub(ctx, "rgb", env, 3);
785+
register_function(ctx, rgb_4_sig, rgb_4, 4, env);
786+
register_function(ctx, rgb_3_sig, rgb_3, 3, env);
787+
register_function(ctx, rgb_2_sig, rgb_2, 2, env);
788+
register_function(ctx, rgb_1_sig, rgb_1, 1, env);
785789

786790
register_overload_stub(ctx, "rgba", env, 4);
787791
register_function(ctx, rgba_4_sig, rgba_4, 4, env);

src/fn_colors.cpp

Lines changed: 139 additions & 130 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,116 @@ namespace Sass {
6868
return value;
6969
}
7070

71+
72+
/// Returns whether [value] is an unquoted string that start with `var(` and
73+
/// contains `/`.
74+
bool _isVarSlash(Expression* value) {
75+
if (String_Constant * string = Cast<String_Constant>(value)) {
76+
return starts_with(string->value(), "var(") &&
77+
string_constains(string->value(), '/');
78+
}
79+
if (StringLiteral * string = Cast<StringLiteral>(value)) {
80+
return starts_with(string->text(), "var(") &&
81+
string_constains(string->text(), '/');
82+
}
83+
return false;
84+
}
85+
86+
87+
Expression* _parseChannels(std::string name, std::vector<std::string> argumentNames, Value* channels, ParserState pstate, Backtraces traces)
88+
{
89+
if (isVar(channels)) {
90+
std::stringstream fncall;
91+
fncall << name << "("
92+
<< channels->to_css() << ")";
93+
return SASS_MEMORY_NEW(StringLiteral,
94+
pstate, fncall.str());
95+
}
96+
97+
// Expression* list = Listize::perform(channels);
98+
99+
if (List * list = Cast<List>(channels)) {
100+
bool isCommaSeparated = list->separator() == SASS_COMMA;
101+
bool isBracketed = list->is_bracketed();
102+
if (isCommaSeparated || isBracketed) {
103+
std::stringstream msg;
104+
msg << "$channels must be";
105+
if (isBracketed) msg << " an unbracketed";
106+
if (isCommaSeparated) {
107+
msg << (isBracketed ? "," : " a");
108+
msg << " space-separated";
109+
}
110+
msg << " list.";
111+
error(msg.str(), pstate, traces);
112+
}
113+
114+
if (list->length() > 3) {
115+
error(
116+
"Only 3 elements allowed, but ${list.length} were passed.",
117+
pstate, traces);
118+
}
119+
else if (list->length() < 3) {
120+
bool hasVar = false;
121+
for (Expression* item : list->elements()) {
122+
if (isVar(item)) {
123+
hasVar = true;
124+
break;
125+
}
126+
}
127+
if (hasVar || (!list->empty() && _isVarSlash(list->last()))) {
128+
std::stringstream fncall;
129+
fncall << name << "(";
130+
for (size_t i = 0, iL = list->length(); i < iL; i++) {
131+
if (i > 0) { fncall << ", "; }
132+
fncall << list->get(i)->to_css();
133+
}
134+
fncall << ")";
135+
return SASS_MEMORY_NEW(StringLiteral,
136+
pstate, fncall.str());
137+
}
138+
else {
139+
std::string argument = argumentNames[list->length()];
140+
error(
141+
"Missing element " + argument + ".",
142+
pstate, traces);
143+
}
144+
}
145+
146+
Number* secondNumber = Cast<Number>(list->get(2));
147+
String_Constant* secondString = Cast<String_Constant>(list->get(2));
148+
if (secondNumber && secondNumber->hasAsSlash()) {
149+
List* rv = SASS_MEMORY_NEW(List, pstate);
150+
rv->append(list->get(0));
151+
rv->append(list->get(1));
152+
rv->append(secondNumber->lhsAsSlash());
153+
rv->append(secondNumber->rhsAsSlash());
154+
return rv;
155+
}
156+
else if (secondString &&
157+
// !maybeSlashSeparated.hasQuotes &&
158+
string_constains(secondString->value(), '/')) {
159+
std::stringstream fncall;
160+
fncall << name << "(";
161+
for (size_t i = 0, iL = list->length(); i < iL; i++) {
162+
if (i > 0) { fncall << ", "; }
163+
fncall << list->get(i)->to_css();
164+
165+
}
166+
fncall << ")";
167+
return SASS_MEMORY_NEW(StringLiteral,
168+
pstate, fncall.str());
169+
}
170+
else {
171+
return list;
172+
}
173+
}
174+
else {
175+
error("$channels must be a space-separated list.",
176+
pstate, traces);
177+
}
178+
return nullptr;
179+
}
180+
71181
AST_Node* getArg(std::string name, Env& env)
72182
{
73183
if (env.has_local(name)) {
@@ -227,154 +337,53 @@ namespace Sass {
227337
return _rgbTwoArg("rgba", env, rgba_2_sig, pstate, traces);
228338
}
229339

230-
/// Returns whether [value] is an unquoted string that start with `var(` and
231-
/// contains `/`.
232-
bool _isVarSlash(Expression* value) {
233-
if (String_Constant * string = Cast<String_Constant>(value)) {
234-
return starts_with(string->value(), "var(") &&
235-
string_constains(string->value(), '/');
340+
Signature rgba_1_sig = "rgba($channels)";
341+
BUILT_IN(rgba_1)
342+
{
343+
Value* channels = ARG("$channels", Value, "a value");
344+
ExpressionObj parsed = _parseChannels("rgba",
345+
{ "$red", "$green", "$blue" }, channels, pstate, traces);
346+
if (StringLiteral * str = Cast<StringLiteral>(parsed)) {
347+
return str;
236348
}
237-
if (StringLiteral * string = Cast<StringLiteral>(value)) {
238-
return starts_with(string->text(), "var(") &&
239-
string_constains(string->text(), '/');
349+
if (List * list = Cast<List>(parsed)) {
350+
return _rgb("rgba", list->elements(), rgba_1_sig, pstate, traces);
240351
}
241-
return false;
352+
return nullptr;
242353
}
243354

244-
245-
Expression* _parseChannels(std::string name, std::vector<std::string> argumentNames, Value* channels, ParserState pstate, Backtraces traces)
355+
Signature rgb_4_sig = "rgb($red, $green, $blue, $alpha)";
356+
BUILT_IN(rgb_4)
246357
{
247-
if (isVar(channels)) {
248-
std::stringstream fncall;
249-
fncall << name << "("
250-
<< channels->to_css() << ")";
251-
return SASS_MEMORY_NEW(StringLiteral,
252-
pstate, fncall.str());
253-
}
254-
255-
// Expression* list = Listize::perform(channels);
256-
257-
if (List * list = Cast<List>(channels)) {
258-
bool isCommaSeparated = list->separator() == SASS_COMMA;
259-
bool isBracketed = list->is_bracketed();
260-
if (isCommaSeparated || isBracketed) {
261-
std::stringstream msg;
262-
msg << "$channels must be";
263-
if (isBracketed) msg << " an unbracketed";
264-
if (isCommaSeparated) {
265-
msg << (isBracketed ? "," : " a");
266-
msg << " space-separated";
267-
}
268-
msg << " list.";
269-
error(msg.str(), pstate, traces);
270-
}
271-
272-
if (list->length() > 3) {
273-
error(
274-
"Only 3 elements allowed, but ${list.length} were passed.",
275-
pstate, traces);
276-
}
277-
else if (list->length() < 3) {
278-
bool hasVar = false;
279-
for (Expression* item : list->elements()) {
280-
if (isVar(item)) {
281-
hasVar = true;
282-
break;
283-
}
284-
}
285-
if (hasVar || (!list->empty() && _isVarSlash(list->last()))) {
286-
std::stringstream fncall;
287-
fncall << name << "(";
288-
for (size_t i = 0, iL = list->length(); i < iL; i++) {
289-
if (i > 0) { fncall << ", "; }
290-
fncall << list->get(i)->to_css();
291-
}
292-
fncall << ")";
293-
return SASS_MEMORY_NEW(StringLiteral,
294-
pstate, fncall.str());
295-
}
296-
else {
297-
std::string argument = argumentNames[list->length()];
298-
error(
299-
"Missing element " + argument + ".",
300-
pstate, traces);
301-
}
302-
}
358+
return _rgb("rgb", env, rgb_4_sig, pstate, traces);
359+
}
303360

304-
Number* secondNumber = Cast<Number>(list->get(2));
305-
String_Constant* secondString = Cast<String_Constant>(list->get(2));
306-
if (secondNumber && secondNumber->hasAsSlash()) {
307-
List* rv = SASS_MEMORY_NEW(List, pstate);
308-
rv->append(list->get(0));
309-
rv->append(list->get(1));
310-
rv->append(secondNumber->lhsAsSlash());
311-
rv->append(secondNumber->rhsAsSlash());
312-
return rv;
313-
}
314-
else if (secondString &&
315-
// !maybeSlashSeparated.hasQuotes &&
316-
string_constains(secondString->value(), '/')) {
317-
std::stringstream fncall;
318-
fncall << name << "(";
319-
for (size_t i = 0, iL = list->length(); i < iL; i++) {
320-
if (i > 0) { fncall << ", "; }
321-
fncall << list->get(i)->to_css();
361+
Signature rgb_3_sig = "rgb($red, $green, $blue)";
362+
BUILT_IN(rgb_3)
363+
{
364+
return _rgb("rgb", env, rgb_3_sig, pstate, traces);
365+
}
322366

323-
}
324-
fncall << ")";
325-
return SASS_MEMORY_NEW(StringLiteral,
326-
pstate, fncall.str());
327-
}
328-
else {
329-
return list;
330-
}
331-
}
332-
else {
333-
error("$channels must be a space-separated list.",
334-
pstate, traces);
335-
}
336-
return nullptr;
367+
Signature rgb_2_sig = "rgb($color, $alpha)";
368+
BUILT_IN(rgb_2)
369+
{
370+
return _rgbTwoArg("rgb", env, rgb_2_sig, pstate, traces);
337371
}
338372

339-
Signature rgba_1_sig = "rgba($channels)";
340-
BUILT_IN(rgba_1)
373+
Signature rgb_1_sig = "rgb($channels)";
374+
BUILT_IN(rgb_1)
341375
{
342376
Value* channels = ARG("$channels", Value, "a value");
343-
ExpressionObj parsed = _parseChannels("rgba",
377+
ExpressionObj parsed = _parseChannels("rgb",
344378
{ "$red", "$green", "$blue" }, channels, pstate, traces);
345379
if (StringLiteral * str = Cast<StringLiteral>(parsed)) {
346380
return str;
347381
}
348382
if (List * list = Cast<List>(parsed)) {
349-
return _rgb("rgb", list->elements(), rgba_1_sig, pstate, traces);
350-
}
351-
}
352-
353-
Signature rgb_sig = "rgb($red, $green, $blue)";
354-
BUILT_IN(rgb)
355-
{
356-
if (
357-
isSpecialNumber(env["$red"]) ||
358-
isSpecialNumber(env["$green"]) ||
359-
isSpecialNumber(env["$blue"])
360-
) {
361-
return SASS_MEMORY_NEW(String_Constant, pstate, "rgb("
362-
+ env["$red"]->to_string()
363-
+ ", "
364-
+ env["$green"]->to_string()
365-
+ ", "
366-
+ env["$blue"]->to_string()
367-
+ ")"
368-
);
383+
return _rgb("rgb", list->elements(), rgb_1_sig, pstate, traces);
369384
}
370-
371-
return SASS_MEMORY_NEW(Color_RGBA,
372-
pstate,
373-
COLOR_NUM("$red"),
374-
COLOR_NUM("$green"),
375-
COLOR_NUM("$blue"));
385+
return nullptr;
376386
}
377-
378387
////////////////
379388
// RGB FUNCTIONS
380389
////////////////

src/fn_colors.hpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@ namespace Sass {
2020
#define COLOR_NUM(argname) color_num(argname, env, sig, pstate, traces) // double
2121
#define ALPHA_NUM(argname) alpha_num(argname, env, sig, pstate, traces) // double
2222

23-
extern Signature rgb_sig;
23+
extern Signature rgb_4_sig;
24+
extern Signature rgb_3_sig;
25+
extern Signature rgb_2_sig;
26+
extern Signature rgb_1_sig;
2427
extern Signature rgba_4_sig;
2528
extern Signature rgba_3_sig;
2629
extern Signature rgba_2_sig;
@@ -55,7 +58,10 @@ namespace Sass {
5558
extern Signature change_color_sig;
5659
extern Signature ie_hex_str_sig;
5760

58-
BUILT_IN(rgb);
61+
BUILT_IN(rgb_1);
62+
BUILT_IN(rgb_2);
63+
BUILT_IN(rgb_3);
64+
BUILT_IN(rgb_4);
5965
BUILT_IN(rgba_4);
6066
BUILT_IN(rgba_3);
6167
BUILT_IN(rgba_2);

0 commit comments

Comments
 (0)