Skip to content

Commit

Permalink
Merge pull request #571 from xzyfer/feat/each-maps-for-realz
Browse files Browse the repository at this point in the history
Add generic support for destructuring assignment in @each
  • Loading branch information
HamptonMakes committed Oct 28, 2014
2 parents 20b2969 + e8c549a commit f55b2d5
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 19 deletions.
6 changes: 3 additions & 3 deletions ast.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -475,11 +475,11 @@ namespace Sass {
// The Sass `@each` control directive.
//////////////////////////////////////
class Each : public Has_Block {
ADD_PROPERTY(string, variable);
ADD_PROPERTY(vector<string>, variables);
ADD_PROPERTY(Expression*, list);
public:
Each(string path, Position position, string var, Expression* lst, Block* b)
: Has_Block(path, position, b), variable_(var), list_(lst)
Each(string path, Position position, vector<string> vars, Expression* lst, Block* b)
: Has_Block(path, position, b), variables_(vars), list_(lst)
{ }
ATTACH_OPERATIONS();
};
Expand Down
2 changes: 1 addition & 1 deletion ast_factory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ namespace Sass {
Comment* new_Comment(string p, size_t l, String* txt);
If* new_If(string p, size_t l, Expression* pred, Block* con, Block* alt = 0);
For* new_For(string p, size_t l, string var, Expression* lo, Expression* hi, Block* b, bool inc);
Each* new_Each(string p, size_t l, string var, Expression* lst, Block* b);
Each* new_Each(string p, size_t l, vector<string> vars, Expression* lst, Block* b);
While* new_While(string p, size_t l, Expression* pred, Block* b);
Extension* new_Extension(string p, size_t l, Selector* s);
Definition<MIXIN>* new_Mixin_Definition(string p, size_t l, string n, Parameters* params, Block* b);
Expand Down
42 changes: 36 additions & 6 deletions eval.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,26 +105,56 @@ namespace Sass {

Expression* Eval::operator()(Each* e)
{
string variable(e->variable());
vector<string> variables(e->variables());
Expression* expr = e->list()->perform(this);
List* list = 0;
Map* map = 0;
if (expr->concrete_type() != Expression::LIST) {
map = static_cast<Map*>(expr);
}
else if (expr->concrete_type() != Expression::LIST) {
list = new (ctx.mem) List(expr->path(), expr->position(), 1, List::COMMA);
*list << expr;
}
else {
list = static_cast<List*>(expr);
}
Env new_env;
new_env[variable] = 0;
for (size_t i = 0, L = variables.size(); i < L; ++i) new_env[variables[i]] = 0;
new_env.link(env);
env = &new_env;
Block* body = e->block();
Expression* val = 0;
for (size_t i = 0, L = list->length(); i < L; ++i) {
(*env)[variable] = (*list)[i];
val = body->perform(this);
if (val) break;

if (map) {
for (auto key : map->keys()) {
(*env)[variables[0]] = key;
(*env)[variables[1]] = map->at(key);
val = body->perform(this);
if (val) break;
}
}
else {
for (size_t i = 0, L = list->length(); i < L; ++i) {
List* variable = 0;
if ((*list)[i]->concrete_type() != Expression::LIST || variables.size() == 1) {
variable = new (ctx.mem) List((*list)[i]->path(), (*list)[i]->position(), 1, List::COMMA);
*variable << (*list)[i];
}
else {
variable = static_cast<List*>((*list)[i]);
}
for (size_t j = 0, K = variables.size(); j < K; ++j) {
if (j < variable->length()) {
(*env)[variables[j]] = (*variable)[j];
}
else {
(*env)[variables[j]] = new (ctx.mem) Null(expr->path(), expr->position());
}
val = body->perform(this);
if (val) break;
}
}
}
env = new_env.parent();
return val;
Expand Down
41 changes: 35 additions & 6 deletions expand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -211,24 +211,53 @@ namespace Sass {

Statement* Expand::operator()(Each* e)
{
string variable(e->variable());
vector<string> variables(e->variables());
Expression* expr = e->list()->perform(eval->with(env, backtrace));
List* list = 0;
if (expr->concrete_type() != Expression::LIST) {
Map* map = 0;
if (expr->concrete_type() == Expression::MAP) {
map = static_cast<Map*>(expr);
}
else if (expr->concrete_type() != Expression::LIST) {
list = new (ctx.mem) List(expr->path(), expr->position(), 1, List::COMMA);
*list << expr;
}
else {
list = static_cast<List*>(expr);
}
Env new_env;
new_env[variable] = 0;
for (size_t i = 0, L = variables.size(); i < L; ++i) new_env[variables[i]] = 0;
new_env.link(env);
env = &new_env;
Block* body = e->block();
for (size_t i = 0, L = list->length(); i < L; ++i) {
(*env)[variable] = (*list)[i]->perform(eval->with(env, backtrace));
append_block(body);

if (map) {
for (auto key : map->keys()) {
(*env)[variables[0]] = key->perform(eval->with(env, backtrace));
(*env)[variables[1]] = map->at(key)->perform(eval->with(env, backtrace));
append_block(body);
}
}
else {
for (size_t i = 0, L = list->length(); i < L; ++i) {
List* variable = 0;
if ((*list)[i]->concrete_type() != Expression::LIST || variables.size() == 1) {
variable = new (ctx.mem) List((*list)[i]->path(), (*list)[i]->position(), 1, List::COMMA);
*variable << (*list)[i];
}
else {
variable = static_cast<List*>((*list)[i]);
}
for (size_t j = 0, K = variables.size(); j < K; ++j) {
if (j < variable->length()) {
(*env)[variables[j]] = (*variable)[j]->perform(eval->with(env, backtrace));
}
else {
(*env)[variables[j]] = new (ctx.mem) Null(expr->path(), expr->position());
}
}
append_block(body);
}
}
env = new_env.parent();
return 0;
Expand Down
6 changes: 5 additions & 1 deletion inspect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,11 @@ namespace Sass {
void Inspect::operator()(Each* loop)
{
append_to_buffer("@each ");
append_to_buffer(loop->variable());
append_to_buffer(loop->variables()[0]);
for (size_t i = 1, L = loop->variables().size(); i < L; ++i) {
append_to_buffer(", ");
append_to_buffer(loop->variables()[i]);
}
append_to_buffer(" in ");
loop->list()->perform(this);
loop->block()->perform(this);
Expand Down
10 changes: 8 additions & 2 deletions parser.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include <cstdlib>
#include <iostream>
#include <vector>
#include "parser.hpp"
#include "file.hpp"
#include "inspect.hpp"
Expand Down Expand Up @@ -1454,7 +1455,12 @@ namespace Sass {
lex < each_directive >();
Position each_source_position = source_position;
if (!lex< variable >()) error("@each directive requires an iteration variable");
string var(Util::normalize_underscores(lexed));
vector<string> vars;
vars.push_back(Util::normalize_underscores(lexed));
while (peek< exactly<','> >() && lex< exactly<','> >()) {
if (!lex< variable >()) error("@each directive requires an iteration variable");
vars.push_back(Util::normalize_underscores(lexed));
}
if (!lex< in >()) error("expected 'in' keyword in @each directive");
Expression* list = parse_list();
list->is_delayed(false);
Expand All @@ -1466,7 +1472,7 @@ namespace Sass {
}
if (!peek< exactly<'{'> >()) error("expected '{' after the upper bound in @each directive");
Block* body = parse_block();
return new (ctx.mem) Each(path, each_source_position, var, list, body);
return new (ctx.mem) Each(path, each_source_position, vars, list, body);
}

While* Parser::parse_while_directive()
Expand Down

0 comments on commit f55b2d5

Please sign in to comment.