Commit a78ca00a by Aaron Leung

Implemented the @each directive.

parent 8354bde2
......@@ -162,7 +162,7 @@ namespace Sass {
Node parse_value_schema();
Node parse_if_directive(Node surrounding_ruleset);
Node parse_for_directive(Node surrounding_ruleset);
Node parse_each_directive(Node surrounding_ruleset);
Selector_Lookahead lookahead_for_selector(const char* start = 0);
......
......@@ -42,6 +42,9 @@ namespace Sass {
else if (peek< for_directive >()) {
root << parse_for_directive(Node());
}
else if (peek< each_directive >()) {
root << parse_each_directive(Node());
}
else {
lex< spaces_and_comments >();
throw_syntax_error("invalid top-level expression");
......@@ -496,6 +499,9 @@ namespace Sass {
else if (peek< for_directive >()) {
block << parse_for_directive(surrounding_ruleset);
}
else if (peek< each_directive >()) {
block << parse_each_directive(surrounding_ruleset);
}
else if (!peek< exactly<';'> >()) {
Node rule(parse_rule());
// check for lbrace; if it's there, we have a namespace property with a value
......@@ -920,10 +926,25 @@ namespace Sass {
Node upper_bound(parse_expression());
if (!peek< exactly<'{'> >()) throw_syntax_error("expected '{' after the upper bound in @for directive");
Node body(parse_block(surrounding_ruleset));
Node loop(context.new_Node(for_type, path, for_line, 3));
Node loop(context.new_Node(for_type, path, for_line, 4));
loop << var << lower_bound << upper_bound << body;
return loop;
}
Node Document::parse_each_directive(Node surrounding_ruleset)
{
lex < each_directive >();
size_t each_line = line;
if (!lex< variable >()) throw_syntax_error("@each directive requires an iteration variable");
Node var(context.new_Node(Node::variable, path, line, lexed));
if (!lex< in >()) throw_syntax_error("expected 'in' keyword in @each directive");
Node list(parse_list());
if (!peek< exactly<'{'> >()) throw_syntax_error("expected '{' after the upper bound in @each directive");
Node body(parse_block(surrounding_ruleset));
Node each(context.new_Node(Node::each_directive, path, each_line, 3));
each << var << list << body;
return each;
}
Selector_Lookahead Document::lookahead_for_selector(const char* start)
{
......
......@@ -342,6 +342,21 @@ namespace Sass {
}
} break;
case Node::each_directive: {
Node fake_mixin(new_Node(Node::mixin, expr.path(), expr.line(), 3));
Node fake_param(new_Node(Node::parameters, expr.path(), expr.line(), 1));
fake_mixin << new_Node(Node::none, "", 0, 0) << (fake_param << expr[0]) << expr[2];
Node list(expr[1]);
expr.pop_back();
expr.pop_back();
expr.pop_back();
for (size_t i = 0, S = list.size(); i < S; ++i) {
Node fake_arg(new_Node(Node::arguments, expr.path(), expr.line(), 1));
fake_arg << eval(list[i], prefix, env, f_env, new_Node, ctx);
expr += apply_mixin(fake_mixin, fake_arg, prefix, env, f_env, new_Node, ctx);
}
} break;
default: {
return expr;
} break;
......
......@@ -16,18 +16,28 @@ namespace Sass {
if (type() != block && type() != expansion && type() != root && type() != for_through_directive && type() != for_to_directive) return;
// size can change during flattening, so we need to call size() on each pass
for (size_t i = 0; i < size(); ++i) {
Type i_type = at(i).type();
if ((i_type == expansion) || (i_type == block) || (i_type == for_through_directive) || (i_type == for_to_directive)) {
Node expn(at(i));
if (expn.has_expansions()) expn.flatten();
ip_->has_statements |= expn.has_statements();
ip_->has_blocks |= expn.has_blocks();
ip_->has_expansions |= expn.has_expansions();
// TO DO: make this more efficient -- replace with a dummy node instead of erasing
ip_->children.erase(begin() + i);
insert(begin() + i, expn.begin(), expn.end());
// skip over what we just spliced in
i += expn.size() - 1;
switch (at(i).type())
{
case expansion:
case block:
case for_through_directive:
case for_to_directive:
case each_directive:
case while_directive: {
Node expn(at(i));
if (expn.has_expansions()) expn.flatten();
ip_->has_statements |= expn.has_statements();
ip_->has_blocks |= expn.has_blocks();
ip_->has_expansions |= expn.has_expansions();
// TO DO: make this more efficient -- replace with a dummy node instead of erasing
ip_->children.erase(begin() + i);
insert(begin() + i, expn.begin(), expn.end());
// skip over what we just spliced in
i += expn.size() - 1;
} break;
default: {
} break;
}
}
}
......
......@@ -152,6 +152,11 @@ namespace Sass {
const char* each_directive(const char* src) {
return exactly<each_kwd>(src);
}
extern const char in_kwd[] = "in";
const char* in(const char* src) {
return exactly<in_kwd>(src);
}
extern const char while_kwd[] = "@while";
const char* while_directive(const char* src) {
return exactly<while_kwd>(src);
......@@ -214,7 +219,7 @@ namespace Sass {
extern const char px_kwd[] = "px";
extern const char cm_kwd[] = "cm";
extern const char mm_kwd[] = "mm";
extern const char in_kwd[] = "in";
// extern const char in_kwd[] = "in";
extern const char pt_kwd[] = "pt";
extern const char pc_kwd[] = "pc";
extern const char deg_kwd[] = "deg";
......
......@@ -322,6 +322,7 @@ namespace Sass {
const char* through(const char* src);
const char* each_directive(const char* src);
const char* in(const char* src);
const char* while_directive(const char* src);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment