Commit 8ef6dc43 by Aaron Leung

Mixins are fully functional. Check out the jankiest usages.

parent 3e5e6bfd
......@@ -7,6 +7,7 @@ namespace Sass {
void Document::parse_scss()
{
lex<optional_spaces>();
root << Node(Node::flags);
while(*position) {
if (lex< block_comment >()) {
root << Node(line_number, Node::comment, lexed);
......@@ -22,7 +23,7 @@ namespace Sass {
Node call(parse_mixin_call());
// call << root;
root << call;
root.has_expansions = true;
root[0].has_expansions = true;
lex< exactly<';'> >();
context.pending.push_back(call);
}
......@@ -303,7 +304,8 @@ namespace Sass {
{
lex< exactly<'{'> >();
bool semicolon = false;
Node block(line_number, Node::block);
Node block(line_number, Node::block, 1);
block << Node(Node::flags);
while (!lex< exactly<'}'> >()) {
if (semicolon) {
lex< exactly<';'> >(); // enforce terminal ';' here
......@@ -312,7 +314,8 @@ namespace Sass {
}
if (lex< block_comment >()) {
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;
}
else if (peek< import >(position)) {
......@@ -321,10 +324,12 @@ namespace Sass {
for (int i = 0; i < imported_tree.size(); ++i) {
if (imported_tree[i].type == Node::comment ||
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) {
block.has_rulesets = true;
// block.has_rulesets = true;
block[0].has_rulesets = true;
}
block << imported_tree[i];
}
......@@ -334,7 +339,8 @@ namespace Sass {
Node call(parse_mixin_call());
// call << block;
block << call;
block.has_expansions = true;
// block.has_expansions = true;
block[0].has_expansions = true;
if (!definition) context.pending.push_back(call);
}
else if (lex< variable >()) {
......@@ -354,16 +360,18 @@ namespace Sass {
// }
else if (const char* p = look_for_selector_group(position)) {
block << parse_ruleset(definition);
block.has_rulesets = true;
block[0].has_rulesets = true;
}
else if (!peek< exactly<';'> >()) {
Node rule(parse_rule());
block << rule;
block.has_rules_or_comments = true;
// block.has_rules_or_comments = true;
block[0].has_rules_or_comments = true;
semicolon = true;
if (!definition && rule[1].eval_me) context.pending.push_back(rule);
}
else lex< exactly<';'> >();
while (lex< block_comment >()) block << Node(line_number, Node::comment, lexed);
}
return block;
}
......
......@@ -24,10 +24,22 @@ namespace Sass {
expr.children->pop_back();
expr.children->pop_back();
expr += expansion;
expr.has_rules_or_comments |= expansion.has_rules_or_comments;
expr.has_rulesets |= expansion.has_rulesets;
expr.has_propsets |= expansion.has_propsets;
expr.has_expansions |= expansion.has_expansions;
// expr[0].has_rules_or_comments |= expansion[0].has_rules_or_comments;
// expr[0].has_rulesets |= expansion[0].has_rulesets;
// expr[0].has_propsets |= expansion[0].has_propsets;
// 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;
} break;
......@@ -233,7 +245,7 @@ namespace Sass {
{
// cerr << "APPLYING MIXIN: " << string(mixin[0].token) << endl;
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());
Environment m_env;
// cerr << "CLONED BODY" << endl;
......@@ -271,7 +283,7 @@ namespace Sass {
for (int i = 0; i < body.size(); ++i) {
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;
}
}
\ No newline at end of file
......@@ -291,32 +291,36 @@ namespace Sass {
switch (type)
{
case root:
if (at(0).has_expansions) {
cerr << "FLATTENING ROOT NODE" << endl;
flatten();
}
for (int i = 0; i < children->size(); ++i) {
children->at(i).emit_nested_css(buf, depth, prefixes);
}
break;
case ruleset: {
Node sel_group(children->at(0));
Node block(children->at(1));
Node sel_group(at(0));
Node block(at(1));
vector<string> new_prefixes;
if (prefixes.empty()) {
new_prefixes.reserve(sel_group.children->size());
for (int i = 0; i < sel_group.children->size(); ++i) {
new_prefixes.push_back(sel_group.children->at(i).to_string(string()));
new_prefixes.reserve(sel_group.size());
for (int i = 0; i < sel_group.size(); ++i) {
new_prefixes.push_back(sel_group[i].to_string(string()));
}
}
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 j = 0; j < sel_group.children->size(); ++j) {
new_prefixes.push_back(sel_group.children->at(j).to_string(prefixes[i]));
for (int j = 0; j < sel_group.size(); ++j) {
new_prefixes.push_back(sel_group[j].to_string(prefixes[i]));
}
}
}
if (block.has_expansions) block.flatten();
if (block.has_rules_or_comments) {
if (block[0].has_expansions) block.flatten();
if (block[0].has_rules_or_comments) {
buf << string(2*depth, ' ') << new_prefixes[0];
for (int i = 1; i < new_prefixes.size(); ++i) {
buf << ", " << new_prefixes[i];
......@@ -337,14 +341,14 @@ namespace Sass {
buf << " }" << endl;
++depth; // if we printed content at this level, we need to indent any nested rulesets
}
if (block.has_rulesets) {
for (int i = 0; i < block.children->size(); ++i) {
if (block.children->at(i).type == ruleset) {
block.children->at(i).emit_nested_css(buf, depth, new_prefixes);
if (block[0].has_rulesets) {
for (int i = 0; i < block.size(); ++i) {
if (block[i].type == ruleset) {
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;
} break;
......@@ -438,12 +442,16 @@ namespace Sass {
void Node::flatten()
{
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) {
if (at(i).type == expansion) {
cerr << "FLATTEN: found an expansion node" << endl;
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;
children->insert(children->begin() + i, expn.children->begin(), expn.children->end());
}
......
......@@ -69,7 +69,8 @@ namespace Sass {
assignment,
comment,
none
none,
flags
};
static size_t fresh;
......@@ -90,6 +91,15 @@ namespace Sass {
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)
: line_number(n.line_number),
children(n.children),
......
$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