Commit 8ef6dc43 by Aaron Leung

Mixins are fully functional. Check out the jankiest usages.

parent 3e5e6bfd
...@@ -7,6 +7,7 @@ namespace Sass { ...@@ -7,6 +7,7 @@ namespace Sass {
void Document::parse_scss() void Document::parse_scss()
{ {
lex<optional_spaces>(); lex<optional_spaces>();
root << Node(Node::flags);
while(*position) { while(*position) {
if (lex< block_comment >()) { if (lex< block_comment >()) {
root << Node(line_number, Node::comment, lexed); root << Node(line_number, Node::comment, lexed);
...@@ -22,7 +23,7 @@ namespace Sass { ...@@ -22,7 +23,7 @@ namespace Sass {
Node call(parse_mixin_call()); Node call(parse_mixin_call());
// call << root; // call << root;
root << call; root << call;
root.has_expansions = true; root[0].has_expansions = true;
lex< exactly<';'> >(); lex< exactly<';'> >();
context.pending.push_back(call); context.pending.push_back(call);
} }
...@@ -303,7 +304,8 @@ namespace Sass { ...@@ -303,7 +304,8 @@ namespace Sass {
{ {
lex< exactly<'{'> >(); lex< exactly<'{'> >();
bool semicolon = false; bool semicolon = false;
Node block(line_number, Node::block); Node block(line_number, Node::block, 1);
block << Node(Node::flags);
while (!lex< exactly<'}'> >()) { while (!lex< exactly<'}'> >()) {
if (semicolon) { if (semicolon) {
lex< exactly<';'> >(); // enforce terminal ';' here lex< exactly<';'> >(); // enforce terminal ';' here
...@@ -312,7 +314,8 @@ namespace Sass { ...@@ -312,7 +314,8 @@ namespace Sass {
} }
if (lex< block_comment >()) { if (lex< block_comment >()) {
block << Node(line_number, Node::comment, lexed); block << Node(line_number, Node::comment, lexed);
block.has_rules_or_comments = true; // block.has_rules_or_comments = true;
block[0].has_rules_or_comments = true;
semicolon = true; semicolon = true;
} }
else if (peek< import >(position)) { else if (peek< import >(position)) {
...@@ -321,10 +324,12 @@ namespace Sass { ...@@ -321,10 +324,12 @@ namespace Sass {
for (int i = 0; i < imported_tree.size(); ++i) { for (int i = 0; i < imported_tree.size(); ++i) {
if (imported_tree[i].type == Node::comment || if (imported_tree[i].type == Node::comment ||
imported_tree[i].type == Node::rule) { imported_tree[i].type == Node::rule) {
block.has_rules_or_comments = true; // block.has_rules_or_comments = true;
block[0].has_rules_or_comments = true;
} }
else if (imported_tree[i].type == Node::ruleset) { else if (imported_tree[i].type == Node::ruleset) {
block.has_rulesets = true; // block.has_rulesets = true;
block[0].has_rulesets = true;
} }
block << imported_tree[i]; block << imported_tree[i];
} }
...@@ -334,7 +339,8 @@ namespace Sass { ...@@ -334,7 +339,8 @@ namespace Sass {
Node call(parse_mixin_call()); Node call(parse_mixin_call());
// call << block; // call << block;
block << call; block << call;
block.has_expansions = true; // block.has_expansions = true;
block[0].has_expansions = true;
if (!definition) context.pending.push_back(call); if (!definition) context.pending.push_back(call);
} }
else if (lex< variable >()) { else if (lex< variable >()) {
...@@ -354,16 +360,18 @@ namespace Sass { ...@@ -354,16 +360,18 @@ namespace Sass {
// } // }
else if (const char* p = look_for_selector_group(position)) { else if (const char* p = look_for_selector_group(position)) {
block << parse_ruleset(definition); block << parse_ruleset(definition);
block.has_rulesets = true; block[0].has_rulesets = true;
} }
else if (!peek< exactly<';'> >()) { else if (!peek< exactly<';'> >()) {
Node rule(parse_rule()); Node rule(parse_rule());
block << rule; block << rule;
block.has_rules_or_comments = true; // block.has_rules_or_comments = true;
block[0].has_rules_or_comments = true;
semicolon = true; semicolon = true;
if (!definition && rule[1].eval_me) context.pending.push_back(rule); if (!definition && rule[1].eval_me) context.pending.push_back(rule);
} }
else lex< exactly<';'> >(); else lex< exactly<';'> >();
while (lex< block_comment >()) block << Node(line_number, Node::comment, lexed);
} }
return block; return block;
} }
......
...@@ -24,10 +24,22 @@ namespace Sass { ...@@ -24,10 +24,22 @@ namespace Sass {
expr.children->pop_back(); expr.children->pop_back();
expr.children->pop_back(); expr.children->pop_back();
expr += expansion; expr += expansion;
expr.has_rules_or_comments |= expansion.has_rules_or_comments; // expr[0].has_rules_or_comments |= expansion[0].has_rules_or_comments;
expr.has_rulesets |= expansion.has_rulesets; // expr[0].has_rulesets |= expansion[0].has_rulesets;
expr.has_propsets |= expansion.has_propsets; // expr[0].has_propsets |= expansion[0].has_propsets;
expr.has_expansions |= expansion.has_expansions; // expr[0].has_expansions |= expansion[0].has_expansions;
return expr;
} break;
case Node::ruleset: {
eval(expr[1], env);
return expr;
} break;
case Node::block: {
for (int i = 0; i < expr.size(); ++i) {
eval(expr[i], env);
}
return expr; return expr;
} break; } break;
...@@ -233,7 +245,7 @@ namespace Sass { ...@@ -233,7 +245,7 @@ namespace Sass {
{ {
// cerr << "APPLYING MIXIN: " << string(mixin[0].token) << endl; // cerr << "APPLYING MIXIN: " << string(mixin[0].token) << endl;
Node params(mixin[1]); Node params(mixin[1]);
if (mixin[2].has_expansions) cerr << "ORIGINAL BODY FOR " << string(mixin[0].token) << " HAS EXPANSIONS" << endl; if (mixin[2][0].has_expansions) cerr << "ORIGINAL BODY FOR " << string(mixin[0].token) << " HAS EXPANSIONS" << endl;
Node body(mixin[2].clone()); Node body(mixin[2].clone());
Environment m_env; Environment m_env;
// cerr << "CLONED BODY" << endl; // cerr << "CLONED BODY" << endl;
...@@ -271,7 +283,7 @@ namespace Sass { ...@@ -271,7 +283,7 @@ namespace Sass {
for (int i = 0; i < body.size(); ++i) { for (int i = 0; i < body.size(); ++i) {
body[i] = eval(body[i], m_env); body[i] = eval(body[i], m_env);
} }
if (body.has_expansions) cerr << "APPLYING MIXIN CONTAINING EXPANSIONS" << endl; if (body[0].has_expansions) cerr << "APPLYING MIXIN CONTAINING EXPANSIONS" << endl;
return body; return body;
} }
} }
\ No newline at end of file
...@@ -291,32 +291,36 @@ namespace Sass { ...@@ -291,32 +291,36 @@ namespace Sass {
switch (type) switch (type)
{ {
case root: case root:
if (at(0).has_expansions) {
cerr << "FLATTENING ROOT NODE" << endl;
flatten();
}
for (int i = 0; i < children->size(); ++i) { for (int i = 0; i < children->size(); ++i) {
children->at(i).emit_nested_css(buf, depth, prefixes); children->at(i).emit_nested_css(buf, depth, prefixes);
} }
break; break;
case ruleset: { case ruleset: {
Node sel_group(children->at(0)); Node sel_group(at(0));
Node block(children->at(1)); Node block(at(1));
vector<string> new_prefixes; vector<string> new_prefixes;
if (prefixes.empty()) { if (prefixes.empty()) {
new_prefixes.reserve(sel_group.children->size()); new_prefixes.reserve(sel_group.size());
for (int i = 0; i < sel_group.children->size(); ++i) { for (int i = 0; i < sel_group.size(); ++i) {
new_prefixes.push_back(sel_group.children->at(i).to_string(string())); new_prefixes.push_back(sel_group[i].to_string(string()));
} }
} }
else { else {
new_prefixes.reserve(prefixes.size() * sel_group.children->size()); new_prefixes.reserve(prefixes.size() * sel_group.size());
for (int i = 0; i < prefixes.size(); ++i) { for (int i = 0; i < prefixes.size(); ++i) {
for (int j = 0; j < sel_group.children->size(); ++j) { for (int j = 0; j < sel_group.size(); ++j) {
new_prefixes.push_back(sel_group.children->at(j).to_string(prefixes[i])); new_prefixes.push_back(sel_group[j].to_string(prefixes[i]));
} }
} }
} }
if (block.has_expansions) block.flatten(); if (block[0].has_expansions) block.flatten();
if (block.has_rules_or_comments) { if (block[0].has_rules_or_comments) {
buf << string(2*depth, ' ') << new_prefixes[0]; buf << string(2*depth, ' ') << new_prefixes[0];
for (int i = 1; i < new_prefixes.size(); ++i) { for (int i = 1; i < new_prefixes.size(); ++i) {
buf << ", " << new_prefixes[i]; buf << ", " << new_prefixes[i];
...@@ -337,14 +341,14 @@ namespace Sass { ...@@ -337,14 +341,14 @@ namespace Sass {
buf << " }" << endl; buf << " }" << endl;
++depth; // if we printed content at this level, we need to indent any nested rulesets ++depth; // if we printed content at this level, we need to indent any nested rulesets
} }
if (block.has_rulesets) { if (block[0].has_rulesets) {
for (int i = 0; i < block.children->size(); ++i) { for (int i = 0; i < block.size(); ++i) {
if (block.children->at(i).type == ruleset) { if (block[i].type == ruleset) {
block.children->at(i).emit_nested_css(buf, depth, new_prefixes); block[i].emit_nested_css(buf, depth, new_prefixes);
} }
} }
} }
if (block.has_rules_or_comments) --depth; if (block[0].has_rules_or_comments) --depth;
if (depth == 0 && prefixes.empty()) buf << endl; if (depth == 0 && prefixes.empty()) buf << endl;
} break; } break;
...@@ -438,12 +442,16 @@ namespace Sass { ...@@ -438,12 +442,16 @@ namespace Sass {
void Node::flatten() void Node::flatten()
{ {
cerr << "FLATTENING A BLOCK" << endl; cerr << "FLATTENING A BLOCK" << endl;
if (type != block && type != expansion) return; if (type != block && type != expansion && type != root) return;
for (int i = 0; i < size(); ++i) { for (int i = 0; i < size(); ++i) {
if (at(i).type == expansion) { if (at(i).type == expansion) {
cerr << "FLATTEN: found an expansion node" << endl; cerr << "FLATTEN: found an expansion node" << endl;
Node expn = at(i); Node expn = at(i);
if (expn.has_expansions) expn.flatten(); if (expn[0].has_expansions) expn.flatten();
at(0).has_rules_or_comments |= expn[0].has_rules_or_comments;
at(0).has_rulesets |= expn[0].has_rulesets;
at(0).has_propsets |= expn[0].has_propsets;
at(0).has_expansions |= expn[0].has_expansions;
at(i).type = none; at(i).type = none;
children->insert(children->begin() + i, expn.children->begin(), expn.children->end()); children->insert(children->begin() + i, expn.children->begin(), expn.children->end());
} }
......
...@@ -69,7 +69,8 @@ namespace Sass { ...@@ -69,7 +69,8 @@ namespace Sass {
assignment, assignment,
comment, comment,
none none,
flags
}; };
static size_t fresh; static size_t fresh;
...@@ -89,6 +90,15 @@ namespace Sass { ...@@ -89,6 +90,15 @@ namespace Sass {
bool eval_me; bool eval_me;
Node() : type(none), children(0) { ++fresh; } Node() : type(none), children(0) { ++fresh; }
Node(Node::Type type)
: type(type),
children(0),
has_rules_or_comments(false),
has_rulesets(false),
has_propsets(false),
has_expansions(false)
{ ++fresh; }
Node(const Node& n) Node(const Node& n)
: line_number(n.line_number), : line_number(n.line_number),
......
$x: global-x;
$y: global-y;
$z: global-z;
@mixin foo($x, $y) {
/* begin foo */
margin: $x $y;
blip {
hey: now;
}
/* end foo */
}
@mixin foogoo($x, $y, $z) {
margin: $x $y $z;
}
@mixin hux($y) {
/* begin hux */
color: $y;
@include foo(called-from-hux);
/* end hux */
}
div {
@include foo(1, 2);
@include foo(1);
@include foogoo(1, 2);
@include foogoo($y /* blah */ : kwd-y, $z: kwd-z);
}
div {
@include hux();
}
$y: different-global-y;
div {
@include hux(calling-hux-again);
}
@mixin bung() {
blah: original-bung;
}
div {
@include bung();
}
@mixin bung() {
blah: redefined-bung;
}
div {
@include bung();
}
div {
/* calls to nullary mixins may omit the empty argument list */
@include bung;
}
div {
@include foo(arg1, arg2, $x: kwdarg1, $y: kwdarg2);
@include foo($x: kwdarg1, $y: kwdarg2, arg1, arg2);
}
@mixin ruleset() {
hoo {
color: boo;
}
}
@include ruleset();
$da: default argument;
@mixin default_args($x, $y: $da) {
blah: $x $y;
}
$da: some other default;
div {
@include default_args(boogoo);
}
@mixin original() {
value: original;
}
div {
@include original();
}
@mixin original() {
value: no longer original;
}
div {
@include original();
}
@mixin set-x($x) {
$x: changed local x;
arg: $x;
$y: changed global y;
blarg: $y;
}
div {
@include set-x(blah);
a: $x;
b: $y;
}
\ No newline at end of file
div {
/* begin foo */
margin: 1 2;
/* end foo */
/* begin foo */
margin: 1 global-y;
/* end foo */
margin: 1 2 global-z;
margin: global-x kwd-y kwd-z; }
div blip {
hey: now; }
div blip {
hey: now; }
div {
/* begin hux */
color: global-y;
/* begin foo */
margin: called-from-hux global-y;
/* end foo */
/* end hux */ }
div blip {
hey: now; }
div {
/* begin hux */
color: calling-hux-again;
/* begin foo */
margin: called-from-hux different-global-y;
/* end foo */
/* end hux */ }
div blip {
hey: now; }
div {
blah: original-bung; }
div {
blah: redefined-bung; }
div {
/* calls to nullary mixins may omit the empty argument list */
blah: redefined-bung; }
div {
/* begin foo */
margin: arg1 arg2;
/* end foo */
/* begin foo */
margin: arg1 arg2;
/* end foo */ }
div blip {
hey: now; }
div blip {
hey: now; }
hoo {
color: boo; }
div {
blah: boogoo some other default; }
div {
value: original; }
div {
value: no longer original; }
div {
arg: changed local x;
blarg: changed global y;
a: global-x;
b: changed global y; }
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