Skip to content

Commit 46f5244

Browse files
authored
Merge pull request #2279 from xzyfer/bracked-lists
Implement 3.5 bracketed lists
2 parents f5c8d35 + f5e58ba commit 46f5244

File tree

11 files changed

+105
-21
lines changed

11 files changed

+105
-21
lines changed

include/sass/values.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,13 @@ enum Sass_Separator {
3535
SASS_HASH
3636
};
3737

38+
// Tags for denoting Sass list delimiters
39+
enum Sass_List_Delimiter {
40+
SASS_NO_DELIMITER,
41+
SASS_PARENTHESIS,
42+
SASS_BRACKETS
43+
};
44+
3845
// Value Operators
3946
enum Sass_OP {
4047
AND, OR, // logical connectives

src/ast.hpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1047,21 +1047,25 @@ namespace Sass {
10471047
private:
10481048
ADD_PROPERTY(enum Sass_Separator, separator)
10491049
ADD_PROPERTY(bool, is_arglist)
1050+
ADD_PROPERTY(enum Sass_List_Delimiter, delimiter)
10501051
ADD_PROPERTY(bool, from_selector)
10511052
public:
10521053
List(ParserState pstate,
1053-
size_t size = 0, enum Sass_Separator sep = SASS_SPACE, bool argl = false)
1054+
size_t size = 0, enum Sass_Separator sep = SASS_SPACE, bool argl = false,
1055+
enum Sass_List_Delimiter delimiter = SASS_NO_DELIMITER)
10541056
: Value(pstate),
10551057
Vectorized<Expression_Obj>(size),
10561058
separator_(sep),
10571059
is_arglist_(argl),
1060+
delimiter_(delimiter),
10581061
from_selector_(false)
10591062
{ concrete_type(LIST); }
10601063
List(const List* ptr)
10611064
: Value(ptr),
10621065
Vectorized<Expression_Obj>(*ptr),
10631066
separator_(ptr->separator_),
10641067
is_arglist_(ptr->is_arglist_),
1068+
delimiter_(ptr->delimiter_),
10651069
from_selector_(ptr->from_selector_)
10661070
{ concrete_type(LIST); }
10671071
std::string type() { return is_arglist_ ? "arglist" : "list"; }
@@ -1070,7 +1074,8 @@ namespace Sass {
10701074
return separator() == SASS_SPACE ?
10711075
" " : (compressed ? "," : ", ");
10721076
}
1073-
bool is_invisible() const { return empty(); }
1077+
bool is_bracketed() const { return delimiter() == SASS_BRACKETS; }
1078+
bool is_invisible() const { return empty() && !is_bracketed(); }
10741079
Expression_Obj value_at_index(size_t i);
10751080

10761081
virtual size_t size() const;

src/context.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -810,6 +810,7 @@ namespace Sass {
810810
register_function(ctx, append_sig, append, env);
811811
register_function(ctx, zip_sig, zip, env);
812812
register_function(ctx, list_separator_sig, list_separator, env);
813+
register_function(ctx, is_bracketed_sig, is_bracketed, env);
813814
// Map Functions
814815
register_function(ctx, map_get_sig, map_get, env);
815816
register_function(ctx, map_merge_sig, map_merge, env);

src/debugger.hpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -594,11 +594,13 @@ inline void debug_ast(AST_Node_Ptr node, std::string ind, Env* env)
594594
std::cerr << ind << "List " << expression;
595595
std::cerr << " (" << pstate_source_position(node) << ")";
596596
std::cerr << " (" << expression->length() << ") " <<
597-
(expression->separator() == SASS_COMMA ? "Comma " : expression->separator() == SASS_HASH ? "Map" : "Space ") <<
597+
(expression->separator() == SASS_COMMA ? "Comma " : expression->separator() == SASS_HASH ? "Map " : "Space ") <<
598+
(expression->delimiter() == SASS_PARENTHESIS ? "Parenthesis " : expression->delimiter() == SASS_BRACKETS ? "Bracket " : "None ") <<
598599
" [delayed: " << expression->is_delayed() << "] " <<
599600
" [interpolant: " << expression->is_interpolant() << "] " <<
600601
" [listized: " << expression->from_selector() << "] " <<
601602
" [arglist: " << expression->is_arglist() << "] " <<
603+
" [expanded: " << expression->is_expanded() << "] " <<
602604
" [hash: " << expression->hash() << "] " <<
603605
std::endl;
604606
for(const auto& i : expression->elements()) { debug_ast(&i, ind + " ", env); }

src/eval.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -461,7 +461,8 @@ namespace Sass {
461461
l->pstate(),
462462
l->length(),
463463
l->separator(),
464-
l->is_arglist());
464+
l->is_arglist(),
465+
l->delimiter());
465466
for (size_t i = 0, L = l->length(); i < L; ++i) {
466467
ll->append((*l)[i]->perform(this));
467468
}

src/functions.cpp

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1304,7 +1304,7 @@ namespace Sass {
13041304
if (l->empty()) error("argument `$list` of `" + std::string(sig) + "` must not be empty", pstate);
13051305
double index = std::floor(n->value() < 0 ? l->length() + n->value() : n->value() - 1);
13061306
if (index < 0 || index > l->length() - 1) error("index out of bounds for `" + std::string(sig) + "`", pstate);
1307-
List_Ptr result = SASS_MEMORY_NEW(List, pstate, l->length(), l->separator());
1307+
List_Ptr result = SASS_MEMORY_NEW(List, pstate, l->length(), l->separator(), false, l->delimiter());
13081308
for (size_t i = 0, L = l->length(); i < L; ++i) {
13091309
result->append(((i == index) ? v : (*l)[i]));
13101310
}
@@ -1330,7 +1330,7 @@ namespace Sass {
13301330
return SASS_MEMORY_NEW(Null, pstate);
13311331
}
13321332

1333-
Signature join_sig = "join($list1, $list2, $separator: auto)";
1333+
Signature join_sig = "join($list1, $list2, $separator: auto, $bracketed: auto)";
13341334
BUILT_IN(join)
13351335
{
13361336
Map_Obj m1 = SASS_MEMORY_CAST(Map, env["$list1"]);
@@ -1339,10 +1339,13 @@ namespace Sass {
13391339
List_Obj l2 = SASS_MEMORY_CAST(List, env["$list2"]);
13401340
String_Constant_Obj sep = ARG("$separator", String_Constant);
13411341
enum Sass_Separator sep_val = (l1 ? l1->separator() : SASS_SPACE);
1342+
Value* bracketed = ARG("$bracketed", Value);
1343+
enum Sass_List_Delimiter delimiter = (l1 ? l1->delimiter() : SASS_NO_DELIMITER);
13421344
if (!l1) {
13431345
l1 = SASS_MEMORY_NEW(List, pstate, 1);
13441346
l1->append(ARG("$list1", Expression));
13451347
sep_val = (l2 ? l2->separator() : SASS_SPACE);
1348+
delimiter = (l2 ? l2->delimiter() : SASS_NO_DELIMITER);
13461349
}
13471350
if (!l2) {
13481351
l2 = SASS_MEMORY_NEW(List, pstate, 1);
@@ -1360,7 +1363,12 @@ namespace Sass {
13601363
if (sep_str == "space") sep_val = SASS_SPACE;
13611364
else if (sep_str == "comma") sep_val = SASS_COMMA;
13621365
else if (sep_str != "auto") error("argument `$separator` of `" + std::string(sig) + "` must be `space`, `comma`, or `auto`", pstate);
1363-
List_Obj result = SASS_MEMORY_NEW(List, pstate, len, sep_val);
1366+
String_Constant_Obj bracketed_as_str = SASS_MEMORY_CAST_PTR(String_Constant, bracketed);
1367+
bool bracketed_is_auto = bracketed_as_str && unquote(bracketed_as_str->value()) == "auto";
1368+
if (!bracketed_is_auto) {
1369+
delimiter = bracketed->is_false() ? SASS_NO_DELIMITER : SASS_BRACKETS;
1370+
}
1371+
List_Obj result = SASS_MEMORY_NEW(List, pstate, len, sep_val, false, delimiter);
13641372
result->concat(&l1);
13651373
result->concat(&l2);
13661374
return result.detach();
@@ -1987,5 +1995,12 @@ namespace Sass {
19871995
return SASS_MEMORY_NEW(String_Quoted, pstate, ss.str());
19881996
}
19891997

1998+
Signature is_bracketed_sig = "is-bracketed($list)";
1999+
BUILT_IN(is_bracketed)
2000+
{
2001+
Value_Obj value = ARG("$list", Value);
2002+
List_Obj list = SASS_MEMORY_CAST(List, value);
2003+
return SASS_MEMORY_NEW(Boolean, pstate, list && list->is_bracketed());
2004+
}
19902005
}
19912006
}

src/functions.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ namespace Sass {
107107
extern Signature is_superselector_sig;
108108
extern Signature simple_selectors_sig;
109109
extern Signature selector_parse_sig;
110+
extern Signature is_bracketed_sig;
110111

111112
BUILT_IN(rgb);
112113
BUILT_IN(rgba_4);
@@ -189,6 +190,7 @@ namespace Sass {
189190
BUILT_IN(is_superselector);
190191
BUILT_IN(simple_selectors);
191192
BUILT_IN(selector_parse);
193+
BUILT_IN(is_bracketed);
192194
}
193195
}
194196

src/inspect.cpp

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -360,10 +360,19 @@ namespace Sass {
360360
append_string(")");
361361
}
362362

363+
std::string Inspect::lbracket(List_Ptr list) {
364+
return list->is_bracketed() ? "[" : "(";
365+
}
366+
367+
std::string Inspect::rbracket(List_Ptr list) {
368+
return list->is_bracketed() ? "]" : ")";
369+
}
370+
363371
void Inspect::operator()(List_Ptr list)
364372
{
365-
if (output_style() == TO_SASS && list->empty()) {
366-
append_string("()");
373+
if (list->empty() && (output_style() == TO_SASS || list->is_bracketed())) {
374+
append_string(lbracket(list));
375+
append_string(rbracket(list));
367376
return;
368377
}
369378
std::string sep(list->separator() == SASS_SPACE ? " " : ",");
@@ -374,19 +383,24 @@ namespace Sass {
374383

375384
bool was_space_array = in_space_array;
376385
bool was_comma_array = in_comma_array;
386+
// if the list is bracketed, always include the left bracket
387+
if (list->is_bracketed()) {
388+
append_string(lbracket(list));
389+
}
377390
// probably ruby sass eqivalent of element_needs_parens
378-
if (output_style() == TO_SASS &&
391+
else if (output_style() == TO_SASS &&
379392
list->length() == 1 &&
380393
!list->from_selector() &&
381394
!SASS_MEMORY_CAST(List, list->at(0)) &&
382-
!SASS_MEMORY_CAST(Selector_List, list->at(0))) {
383-
append_string("(");
395+
!SASS_MEMORY_CAST(Selector_List, list->at(0))
396+
) {
397+
append_string(lbracket(list));
384398
}
385399
else if (!in_declaration && (list->separator() == SASS_HASH ||
386400
(list->separator() == SASS_SPACE && in_space_array) ||
387401
(list->separator() == SASS_COMMA && in_comma_array)
388402
)) {
389-
append_string("(");
403+
append_string(lbracket(list));
390404
}
391405

392406
if (list->separator() == SASS_SPACE) in_space_array = true;
@@ -415,19 +429,29 @@ namespace Sass {
415429

416430
in_comma_array = was_comma_array;
417431
in_space_array = was_space_array;
432+
433+
// if the list is bracketed, always include the right bracket
434+
if (list->is_bracketed()) {
435+
if (list->separator() == SASS_COMMA && list->size() == 1) {
436+
append_string(",");
437+
}
438+
append_string(rbracket(list));
439+
}
418440
// probably ruby sass eqivalent of element_needs_parens
419-
if (output_style() == TO_SASS &&
441+
else if (output_style() == TO_SASS &&
420442
list->length() == 1 &&
421443
!list->from_selector() &&
422444
!SASS_MEMORY_CAST(List, list->at(0)) &&
423-
!SASS_MEMORY_CAST(Selector_List, list->at(0))) {
424-
append_string(",)");
445+
!SASS_MEMORY_CAST(Selector_List, list->at(0))
446+
) {
447+
append_string(",");
448+
append_string(rbracket(list));
425449
}
426450
else if (!in_declaration && (list->separator() == SASS_HASH ||
427451
(list->separator() == SASS_SPACE && in_space_array) ||
428452
(list->separator() == SASS_COMMA && in_comma_array)
429453
)) {
430-
append_string(")");
454+
append_string(rbracket(list));
431455
}
432456

433457
}

src/inspect.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,9 @@ namespace Sass {
9292
virtual void operator()(Complex_Selector_Ptr);
9393
virtual void operator()(Selector_List_Ptr);
9494

95+
virtual std::string lbracket(List_Ptr);
96+
virtual std::string rbracket(List_Ptr);
97+
9598
// template <typename U>
9699
// void fallback(U x) { fallback_impl(reinterpret_cast<AST_Node_Ptr>(x)); }
97100
};

src/output.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ namespace Sass {
155155
Expression_Ptr item = &list->at(list_i);
156156
if (!item->is_invisible()) all_invisible = false;
157157
}
158-
if (all_invisible) bPrintExpression = false;
158+
if (all_invisible && !list->is_bracketed()) bPrintExpression = false;
159159
}
160160
}
161161
// Print if OK

0 commit comments

Comments
 (0)