Commit 467c22e3 by Aaron Leung

Simplifying the emitter now that selectors are all expanded beforehand.

parent bbd04d5e
...@@ -108,7 +108,7 @@ namespace Sass { ...@@ -108,7 +108,7 @@ namespace Sass {
root.echo(output); root.echo(output);
break; break;
case nested: case nested:
root.emit_nested_css(output, 0, vector<string>()); root.emit_nested_css(output, 0);
break; break;
case expanded: case expanded:
root.emit_expanded_css(output, ""); root.emit_expanded_css(output, "");
......
...@@ -49,10 +49,11 @@ namespace Sass { ...@@ -49,10 +49,11 @@ namespace Sass {
expr[0] = eval(expr[0], prefix, env, f_env, new_Node, ctx); expr[0] = eval(expr[0], prefix, env, f_env, new_Node, ctx);
} }
// expand the selector with the prefix and save it in expr[2] // expand the selector with the prefix and save it in expr[2]
// cerr << "ABOUT TO EXPAND " << expr[0].to_string() << " WITH " << prefix.to_string() << endl;
expr << expand_selector(expr[0], prefix, new_Node); expr << expand_selector(expr[0], prefix, new_Node);
// cerr << "EXPANDED SELECTOR: " << expr.back().to_string("") << endl; // cerr << "EXPANDED SELECTOR: " << expr.back().to_string() << endl;
// eval the body with the current selector as the prefix // eval the body with the current selector as the prefix
eval(expr[1], expr[0], env, f_env, new_Node, ctx); eval(expr[1], expr.back(), env, f_env, new_Node, ctx);
return expr; return expr;
} break; } break;
...@@ -64,7 +65,7 @@ namespace Sass { ...@@ -64,7 +65,7 @@ namespace Sass {
expansion += expr[i].token().unquote(); expansion += expr[i].token().unquote();
} }
else { else {
expansion += expr[i].to_string(""); expansion += expr[i].to_string();
} }
} }
expansion += " {"; // the parser looks for an lbrace to end a selector expansion += " {"; // the parser looks for an lbrace to end a selector
...@@ -355,7 +356,7 @@ namespace Sass { ...@@ -355,7 +356,7 @@ namespace Sass {
acc << new_Node(acc.path(), acc.line(), r, g, b, a); acc << new_Node(acc.path(), acc.line(), r, g, b, a);
} }
else if (lhs.type() == Node::numeric_color && rhs.type() == Node::numeric_color) { else if (lhs.type() == Node::numeric_color && rhs.type() == Node::numeric_color) {
if (lhs[3].numeric_value() != rhs[3].numeric_value()) throw_eval_error("alpha channels must be equal for " + lhs.to_string("") + " + " + rhs.to_string(""), lhs.path(), lhs.line()); if (lhs[3].numeric_value() != rhs[3].numeric_value()) throw_eval_error("alpha channels must be equal for " + lhs.to_string() + " + " + rhs.to_string(), lhs.path(), lhs.line());
double r = operate(op, lhs[0].numeric_value(), rhs[0].numeric_value()); double r = operate(op, lhs[0].numeric_value(), rhs[0].numeric_value());
double g = operate(op, lhs[1].numeric_value(), rhs[1].numeric_value()); double g = operate(op, lhs[1].numeric_value(), rhs[1].numeric_value());
double b = operate(op, lhs[2].numeric_value(), rhs[2].numeric_value()); double b = operate(op, lhs[2].numeric_value(), rhs[2].numeric_value());
...@@ -403,7 +404,7 @@ namespace Sass { ...@@ -403,7 +404,7 @@ namespace Sass {
break; break;
} }
} }
if (!valid_param) throw_eval_error("mixin " + mixin[0].to_string("") + " has no parameter named " + name.to_string(), arg.path(), arg.line()); if (!valid_param) throw_eval_error("mixin " + mixin[0].to_string() + " has no parameter named " + name.to_string(), arg.path(), arg.line());
if (!bindings.query(name)) { if (!bindings.query(name)) {
bindings[name] = eval(arg[1], prefix, env, f_env, new_Node, ctx); bindings[name] = eval(arg[1], prefix, env, f_env, new_Node, ctx);
} }
...@@ -412,7 +413,7 @@ namespace Sass { ...@@ -412,7 +413,7 @@ namespace Sass {
// ensure that the number of ordinal args < params.size() // ensure that the number of ordinal args < params.size()
if (j >= params.size()) { if (j >= params.size()) {
stringstream ss; stringstream ss;
ss << "mixin " << mixin[0].to_string("") << " only takes " << params.size() << ((params.size() == 1) ? " argument" : " arguments"); ss << "mixin " << mixin[0].to_string() << " only takes " << params.size() << ((params.size() == 1) ? " argument" : " arguments");
throw_eval_error(ss.str(), args[i].path(), args[i].line()); throw_eval_error(ss.str(), args[i].path(), args[i].line());
} }
Node param(params[j]); Node param(params[j]);
...@@ -496,8 +497,8 @@ namespace Sass { ...@@ -496,8 +497,8 @@ namespace Sass {
for (size_t i = 0, S = pre.size(); i < S; ++i) { for (size_t i = 0, S = pre.size(); i < S; ++i) {
for (size_t j = 0, T = sel.size(); j < T; ++j) { for (size_t j = 0, T = sel.size(); j < T; ++j) {
Node new_sel(new_Node(Node::selector, sel.path(), sel.line(), 2)); Node new_sel(new_Node(Node::selector, sel.path(), sel.line(), 2));
if (pre[i].type() == Node::selector) new_sel += pre; if (pre[i].type() == Node::selector) new_sel += pre[i];
else new_sel << pre; else new_sel << pre[i];
if (sel[j].type() == Node::selector) new_sel += sel[j]; if (sel[j].type() == Node::selector) new_sel += sel[j];
else new_sel << sel[j]; else new_sel << sel[j];
group << new_sel; group << new_sel;
...@@ -509,8 +510,8 @@ namespace Sass { ...@@ -509,8 +510,8 @@ namespace Sass {
Node group(new_Node(Node::selector_group, sel.path(), sel.line(), pre.size())); Node group(new_Node(Node::selector_group, sel.path(), sel.line(), pre.size()));
for (size_t i = 0, S = pre.size(); i < S; ++i) { for (size_t i = 0, S = pre.size(); i < S; ++i) {
Node new_sel(new_Node(Node::selector, sel.path(), sel.line(), 2)); Node new_sel(new_Node(Node::selector, sel.path(), sel.line(), 2));
if (pre[i].type() == Node::selector) new_sel += pre; if (pre[i].type() == Node::selector) new_sel += pre[i];
else new_sel << pre; else new_sel << pre[i];
if (sel.type() == Node::selector) new_sel += sel; if (sel.type() == Node::selector) new_sel += sel;
else new_sel << sel; else new_sel << sel;
group << new_sel; group << new_sel;
......
...@@ -198,10 +198,7 @@ namespace Sass { ...@@ -198,10 +198,7 @@ namespace Sass {
bool operator>(Node rhs) const; bool operator>(Node rhs) const;
bool operator>=(Node rhs) const; bool operator>=(Node rhs) const;
string to_string(const string& prefix) const; string to_string() const;
void emit_nested_css(stringstream& buf,
size_t depth,
const vector<string>& prefixes);
void emit_nested_css(stringstream& buf, size_t depth); void emit_nested_css(stringstream& buf, size_t depth);
void emit_propset(stringstream& buf, size_t depth, const string& prefix); void emit_propset(stringstream& buf, size_t depth, const string& prefix);
void echo(stringstream& buf, size_t depth = 0); void echo(stringstream& buf, size_t depth = 0);
......
...@@ -15,134 +15,103 @@ using std::endl; ...@@ -15,134 +15,103 @@ using std::endl;
namespace Sass { namespace Sass {
string Node::to_string(const string& prefix) const string Node::to_string() const
{ {
switch (type()) switch (type())
{ {
case selector_group: { // really only needed for arg to :not case selector_group: { // really only needed for arg to :not
string result(at(0).to_string("")); string result(at(0).to_string());
for (size_t i = 1, S = size(); i < S; ++i) { for (size_t i = 1, S = size(); i < S; ++i) {
result += ", "; result += ", ";
result += at(i).to_string(""); result += at(i).to_string();
} }
return result; return result;
} break; } break;
case selector: { case selector: {
string result; string result;
if (!has_backref() && !prefix.empty()) {
result += prefix;
result += ' ';
}
result += at(0).to_string(at(0).has_backref() ? prefix : "");
result += at(0).to_string();
for (size_t i = 1, S = size(); i < S; ++i) { for (size_t i = 1, S = size(); i < S; ++i) {
result += " "; result += " ";
result += at(i).to_string(at(i).has_backref() ? prefix : ""); result += at(i).to_string();
} }
return result; return result;
} break; } break;
case selector_combinator: { case selector_combinator: {
string result(prefix.empty() ? "" : prefix + " "); return token().to_string();
result += token().to_string();
return result;
} break; } break;
case simple_selector_sequence: { case simple_selector_sequence: {
string result; string result;
if (!has_backref() && !prefix.empty()) {
result += prefix;
result += " ";
}
for (size_t i = 0, S = size(); i < S; ++i) { for (size_t i = 0, S = size(); i < S; ++i) {
Node::Type t = at(i).type(); result += at(i).to_string();
result += at(i).to_string(t == backref ? prefix : "");
} }
return result; return result;
} break; } break;
case pseudo: case pseudo:
case simple_selector: { case simple_selector: {
string result(prefix); return token().to_string();
if (!prefix.empty()) result += " ";
result += token().to_string();
return result;
} break; } break;
case pseudo_negation: { case pseudo_negation: {
string result(prefix); string result;
if (!prefix.empty()) result += " "; result += at(0).to_string();
result += at(0).to_string(""); result += at(1).to_string();
result += at(1).to_string("");
result += ')'; result += ')';
return result; return result;
} break; } break;
case functional_pseudo: { case functional_pseudo: {
string result(prefix); string result;
if (!prefix.empty()) result += " "; result += at(0).to_string();
result += at(0).to_string("");
for (size_t i = 1, S = size(); i < S; ++i) { for (size_t i = 1, S = size(); i < S; ++i) {
result += at(i).to_string(""); result += at(i).to_string();
} }
result += ')'; result += ')';
return result; return result;
} break; } break;
case attribute_selector: { case attribute_selector: {
string result(prefix); string result;
if (!prefix.empty()) result += " ";
result += "["; result += "[";
for (size_t i = 0, S = size(); i < S; ++i)
{ result += at(i).to_string(prefix); }
result += ']';
return result;
} break;
case backref: {
return prefix;
} break;
case selector_schema: {
string result(prefix);
if (!result.empty()) result += " ";
for (size_t i = 0, S = size(); i < S; ++i) { for (size_t i = 0, S = size(); i < S; ++i) {
if (at(i).type() == identifier) result += at(i).to_string(""); result += at(i).to_string();
else result += "[INTERPOLANT]";
} }
result += ']';
return result; return result;
} break; } break;
case comma_list: { case comma_list: {
string result(at(0).to_string(prefix)); string result(at(0).to_string());
for (size_t i = 1, S = size(); i < S; ++i) { for (size_t i = 1, S = size(); i < S; ++i) {
if (at(i).type() == nil) continue; if (at(i).type() == nil) continue;
result += ", "; result += ", ";
result += at(i).to_string(prefix); result += at(i).to_string();
} }
return result; return result;
} break; } break;
case space_list: { case space_list: {
string result(at(0).to_string(prefix)); string result(at(0).to_string());
for (size_t i = 1, S = size(); i < S; ++i) { for (size_t i = 1, S = size(); i < S; ++i) {
if (at(i).type() == nil) continue; if (at(i).type() == nil) continue;
result += " "; result += " ";
result += at(i).to_string(prefix); result += at(i).to_string();
} }
return result; return result;
} break; } break;
case expression: case expression:
case term: { case term: {
string result(at(0).to_string(prefix)); string result(at(0).to_string());
for (size_t i = 1, S = size(); i < S; ++i) { for (size_t i = 1, S = size(); i < S; ++i) {
if (!(at(i).type() == add || if (!(at(i).type() == add ||
// at(i).type == sub || // another edge case -- consider uncommenting // at(i).type == sub || // another edge case -- consider uncommenting
at(i).type() == mul)) { at(i).type() == mul)) {
result += at(i).to_string(prefix); result += at(i).to_string();
} }
} }
return result; return result;
...@@ -160,7 +129,7 @@ namespace Sass { ...@@ -160,7 +129,7 @@ namespace Sass {
case css_import: { case css_import: {
stringstream ss; stringstream ss;
ss << "@import url("; ss << "@import url(";
ss << at(0).to_string(""); ss << at(0).to_string();
// cerr << content.token.to_string() << endl; // cerr << content.token.to_string() << endl;
ss << ")"; ss << ")";
return ss.str(); return ss.str();
...@@ -168,9 +137,9 @@ namespace Sass { ...@@ -168,9 +137,9 @@ namespace Sass {
case function_call: { case function_call: {
stringstream ss; stringstream ss;
ss << at(0).to_string(""); ss << at(0).to_string();
ss << "("; ss << "(";
ss << at(1).to_string(""); ss << at(1).to_string();
ss << ")"; ss << ")";
return ss.str(); return ss.str();
} }
...@@ -179,10 +148,10 @@ namespace Sass { ...@@ -179,10 +148,10 @@ namespace Sass {
stringstream ss; stringstream ss;
size_t S = size(); size_t S = size();
if (S > 0) { if (S > 0) {
ss << at(0).to_string(""); ss << at(0).to_string();
for (size_t i = 1; i < S; ++i) { for (size_t i = 1; i < S; ++i) {
ss << ", "; ss << ", ";
ss << at(i).to_string(""); ss << at(i).to_string();
} }
} }
return ss.str(); return ss.str();
...@@ -191,14 +160,14 @@ namespace Sass { ...@@ -191,14 +160,14 @@ namespace Sass {
case unary_plus: { case unary_plus: {
stringstream ss; stringstream ss;
ss << "+"; ss << "+";
ss << at(0).to_string(""); ss << at(0).to_string();
return ss.str(); return ss.str();
} }
case unary_minus: { case unary_minus: {
stringstream ss; stringstream ss;
ss << "-"; ss << "-";
ss << at(0).to_string(""); ss << at(0).to_string();
return ss.str(); return ss.str();
} }
...@@ -300,14 +269,14 @@ namespace Sass { ...@@ -300,14 +269,14 @@ namespace Sass {
case value_schema: { case value_schema: {
string result; string result;
for (size_t i = 0, S = size(); i < S; ++i) result += at(i).to_string(""); for (size_t i = 0, S = size(); i < S; ++i) result += at(i).to_string();
return result; return result;
} break; } break;
case string_schema: { case string_schema: {
string result; string result;
for (size_t i = 0, S = size(); i < S; ++i) { for (size_t i = 0, S = size(); i < S; ++i) {
string chunk(at(i).to_string("")); string chunk(at(i).to_string());
if (at(i).type() == string_constant) { if (at(i).type() == string_constant) {
result += chunk.substr(1, chunk.size()-2); result += chunk.substr(1, chunk.size()-2);
} }
...@@ -326,51 +295,30 @@ namespace Sass { ...@@ -326,51 +295,30 @@ namespace Sass {
} }
} }
void Node::emit_nested_css(stringstream& buf, void Node::emit_nested_css(stringstream& buf, size_t depth)
size_t depth,
const vector<string>& prefixes)
{ {
switch (type()) switch (type())
{ {
case root: case root:
if (has_expansions()) flatten(); if (has_expansions()) flatten();
for (size_t i = 0, S = size(); i < S; ++i) { for (size_t i = 0, S = size(); i < S; ++i) {
at(i).emit_nested_css(buf, depth, prefixes); at(i).emit_nested_css(buf, depth);
} }
break; break;
case ruleset: { case ruleset: {
Node sel_group(at(0)); Node sel_group(at(2));
size_t sel_group_size = (sel_group.type() == selector_group) ? sel_group.size() : 1; // parser ensures no singletons
Node block(at(1)); Node block(at(1));
vector<string> new_prefixes;
if (prefixes.empty()) {
new_prefixes.reserve(sel_group_size);
for (size_t i = 0; i < sel_group_size; ++i) {
new_prefixes.push_back(sel_group_size > 1 ? sel_group[i].to_string("") : sel_group.to_string(""));
}
}
else {
size_t PS = prefixes.size();
new_prefixes.reserve(PS * sel_group_size);
for (size_t i = 0; i < PS; ++i) {
for (size_t j = 0; j < sel_group_size; ++j) {
new_prefixes.push_back(sel_group_size > 1 ? sel_group[j].to_string(prefixes[i]) : sel_group.to_string(prefixes[i]));
}
}
}
if (block.has_expansions()) block.flatten(); if (block.has_expansions()) block.flatten();
if (block.has_statements()) { if (block.has_statements()) {
buf << string(2*depth, ' ') << new_prefixes[0]; buf << string(2*depth, ' ');
for (size_t i = 1, S = new_prefixes.size(); i < S; ++i) { buf << sel_group.to_string();
buf << ", " << new_prefixes[i];
}
buf << " {"; buf << " {";
for (size_t i = 0, S = block.size(); i < S; ++i) { for (size_t i = 0, S = block.size(); i < S; ++i) {
Type stm_type = block[i].type(); Type stm_type = block[i].type();
if (stm_type == comment || stm_type == rule || stm_type == css_import || stm_type == propset) { if (stm_type == comment || stm_type == rule || stm_type == css_import || stm_type == propset) {
block[i].emit_nested_css(buf, depth+1); // USE OVERLOADED VERSION FOR COMMENTS AND RULES block[i].emit_nested_css(buf, depth+1);
} }
} }
buf << " }" << endl; buf << " }" << endl;
...@@ -379,64 +327,98 @@ namespace Sass { ...@@ -379,64 +327,98 @@ namespace Sass {
if (block.has_blocks()) { if (block.has_blocks()) {
for (size_t i = 0, S = block.size(); i < S; ++i) { for (size_t i = 0, S = block.size(); i < S; ++i) {
if (block[i].type() == ruleset) { if (block[i].type() == ruleset) {
block[i].emit_nested_css(buf, depth, new_prefixes); block[i].emit_nested_css(buf, depth);
} }
} }
} }
if (block.has_statements()) --depth; // see previous comment if (block.has_statements()) --depth; // see previous comment
if (depth == 0 && prefixes.empty()) buf << endl; if (depth == 0) buf << endl;
} break; } break;
default:
emit_nested_css(buf, depth); // pass it along to the simpler version
break;
}
}
void Node::emit_nested_css(stringstream& buf, size_t depth)
{
switch (type())
{
case propset: { case propset: {
emit_propset(buf, depth, ""); emit_propset(buf, depth, "");
} break; } break;
case rule: case rule: {
buf << endl << string(2*depth, ' '); buf << endl << string(2*depth, ' ');
at(0).emit_nested_css(buf, depth); // property at(0).emit_nested_css(buf, depth); // property
at(1).emit_nested_css(buf, depth); // values at(1).emit_nested_css(buf, depth); // values
buf << ";"; buf << ";";
break; } break;
case css_import: case css_import: {
buf << string(2*depth, ' '); buf << string(2*depth, ' ');
buf << to_string(""); buf << to_string();
buf << ";" << endl; buf << ";" << endl;
break; } break;
case property: case property: {
buf << token().to_string() << ": "; buf << token().to_string() << ": ";
break; } break;
case values: case values: {
for (size_t i = 0, S = size(); i < S; ++i) { for (size_t i = 0, S = size(); i < S; ++i) {
buf << " " << at(i).token().to_string(); buf << " " << at(i).token().to_string();
} }
break; } break;
case comment: case comment: {
if (depth != 0) buf << endl; if (depth != 0) buf << endl;
buf << string(2*depth, ' ') << token().to_string(); buf << string(2*depth, ' ') << token().to_string();
if (depth == 0) buf << endl; if (depth == 0) buf << endl;
break; } break;
default: default: {
buf << to_string(""); buf << to_string();
break; } break;
} }
} }
void Node::emit_propset(stringstream& buf, size_t depth, const string& prefix) { // void Node::emit_nested_css(stringstream& buf, size_t depth)
// {
// switch (type())
// {
// case propset: {
// emit_propset(buf, depth, "");
// } break;
// case rule:
// buf << endl << string(2*depth, ' ');
// at(0).emit_nested_css(buf, depth); // property
// at(1).emit_nested_css(buf, depth); // values
// buf << ";";
// break;
// case css_import:
// buf << string(2*depth, ' ');
// buf << to_string("");
// buf << ";" << endl;
// break;
// case property:
// buf << token().to_string() << ": ";
// break;
// case values:
// for (size_t i = 0, S = size(); i < S; ++i) {
// buf << " " << at(i).token().to_string();
// }
// break;
// case comment:
// if (depth != 0) buf << endl;
// buf << string(2*depth, ' ') << token().to_string();
// if (depth == 0) buf << endl;
// break;
// default:
// buf << to_string("");
// break;
// }
// }
void Node::emit_propset(stringstream& buf, size_t depth, const string& prefix)
{
string new_prefix(prefix); string new_prefix(prefix);
// bool has_prefix = false; // bool has_prefix = false;
if (new_prefix.empty()) { if (new_prefix.empty()) {
......
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