Commit 9a4adae7 by Aaron Leung

Evaluating function nodes a little more economically.

parent 48c8fbdb
...@@ -202,7 +202,7 @@ namespace Sass { ...@@ -202,7 +202,7 @@ namespace Sass {
if (!lex< identifier >()) throw_syntax_error("invalid name in @include directive"); if (!lex< identifier >()) throw_syntax_error("invalid name in @include directive");
Node name(context.new_Node(Node::identifier, path, line, lexed)); Node name(context.new_Node(Node::identifier, path, line, lexed));
Node args(parse_arguments()); Node args(parse_arguments());
Node the_call(context.new_Node(Node::expansion, path, line, 2)); Node the_call(context.new_Node(Node::mixin_call, path, line, 2));
the_call << name << args; the_call << name << args;
return the_call; return the_call;
} }
......
...@@ -39,7 +39,7 @@ namespace Sass { ...@@ -39,7 +39,7 @@ namespace Sass {
f_env[expr[0].to_string()] = Function(expr); f_env[expr[0].to_string()] = Function(expr);
} break; } break;
case Node::expansion: { // mixin invocation case Node::mixin_call: { // mixin invocation
Token name(expr[0].token()); Token name(expr[0].token());
Node args(expr[1]); Node args(expr[1]);
if (!env.query(name)) throw_eval_error("mixin " + name.to_string() + " is undefined", expr.path(), expr.line()); if (!env.query(name)) throw_eval_error("mixin " + name.to_string() + " is undefined", expr.path(), expr.line());
...@@ -766,42 +766,44 @@ namespace Sass { ...@@ -766,42 +766,44 @@ namespace Sass {
switch (stm.type()) switch (stm.type())
{ {
case Node::assignment: { case Node::assignment: {
Node val(new_Node(stm[1])); // clone the value because it might get mutated in place Node val(stm[1]);
Node newval;
if (val.type() == Node::list) { if (val.type() == Node::list) {
newval = new_Node(Node::list, val.path(), val.line(), val.size());
for (size_t i = 0, S = val.size(); i < S; ++i) { for (size_t i = 0, S = val.size(); i < S; ++i) {
if (val[i].should_eval()) val[i] = eval(val[i], Node(), bindings, ctx.function_env, new_Node, ctx); if (val[i].should_eval()) newval << eval(val[i], Node(), bindings, ctx.function_env, new_Node, ctx);
else newval << val[i];
} }
} }
else { else {
val = eval(val, Node(), bindings, ctx.function_env, new_Node, ctx); newval = eval(val, Node(), bindings, ctx.function_env, new_Node, ctx);
} }
Node var(stm[0]); Node var(stm[0]);
if (stm.is_guarded() && bindings.query(var.token())) continue; if (stm.is_guarded() && bindings.query(var.token())) continue;
// If a binding exists (possibly upframe), then update it. // If a binding exists (possibly upframe), then update it.
// Otherwise, make a new one in the current frame. // Otherwise, make a new one in the current frame.
if (bindings.query(var.token())) { if (bindings.query(var.token())) {
bindings[var.token()] = val; bindings[var.token()] = newval;
} }
else { else {
bindings.current_frame[var.token()] = val; bindings.current_frame[var.token()] = newval;
} }
} break; } break;
case Node::if_directive: { case Node::if_directive: {
for (size_t j = 0, S = stm.size(); j < S; j += 2) { for (size_t j = 0, S = stm.size(); j < S; j += 2) {
if (stm[j].type() != Node::block) { if (stm[j].type() != Node::block) {
Node pred(new_Node(stm[j])); Node predicate_val(eval(stm[j], Node(), bindings, ctx.function_env, new_Node, ctx));
Node predicate_val(eval(pred, Node(), bindings, ctx.function_env, new_Node, ctx)); if (!predicate_val.is_false()) {
if ((predicate_val.type() != Node::boolean) || predicate_val.boolean_value()) {
Node v(eval_function(name, stm[j+1], bindings, new_Node, ctx)); Node v(eval_function(name, stm[j+1], bindings, new_Node, ctx));
if (v.is_null()) break; if (v.is_null()) break;
else return v; else return v;
} }
} }
else { else {
Node v(eval_function(name, stm[j], bindings, new_Node, ctx)); Node v(eval_function(name, stm[j], bindings, new_Node, ctx));
if (v.is_null()) break; if (v.is_null()) break;
else return v; else return v;
} }
} }
} break; } break;
...@@ -810,8 +812,8 @@ namespace Sass { ...@@ -810,8 +812,8 @@ namespace Sass {
case Node::for_to_directive: { case Node::for_to_directive: {
Node::Type for_type = stm.type(); Node::Type for_type = stm.type();
Node iter_var(stm[0]); Node iter_var(stm[0]);
Node lower_bound(eval(new_Node(stm[1]), Node(), bindings, ctx.function_env, new_Node, ctx)); Node lower_bound(eval(stm[1], Node(), bindings, ctx.function_env, new_Node, ctx));
Node upper_bound(eval(new_Node(stm[2]), Node(), bindings, ctx.function_env, new_Node, ctx)); Node upper_bound(eval(stm[2], Node(), bindings, ctx.function_env, new_Node, ctx));
Node for_body(stm[3]); Node for_body(stm[3]);
Environment for_env; // re-use this env for each iteration Environment for_env; // re-use this env for each iteration
for_env.link(bindings); for_env.link(bindings);
...@@ -821,13 +823,13 @@ namespace Sass { ...@@ -821,13 +823,13 @@ namespace Sass {
for_env.current_frame[iter_var.token()] = new_Node(lower_bound.path(), lower_bound.line(), j); for_env.current_frame[iter_var.token()] = new_Node(lower_bound.path(), lower_bound.line(), j);
Node v(eval_function(name, for_body, for_env, new_Node, ctx)); Node v(eval_function(name, for_body, for_env, new_Node, ctx));
if (v.is_null()) continue; if (v.is_null()) continue;
else return v; else return v;
} }
} break; } break;
case Node::each_directive: { case Node::each_directive: {
Node iter_var(stm[0]); Node iter_var(stm[0]);
Node list(eval(new_Node(stm[1]), Node(), bindings, ctx.function_env, new_Node, ctx)); Node list(eval(stm[1], Node(), bindings, ctx.function_env, new_Node, ctx));
if (list.type() != Node::list) { if (list.type() != Node::list) {
list = (new_Node(Node::list, list.path(), list.line(), 1) << list); list = (new_Node(Node::list, list.path(), list.line(), 1) << list);
} }
...@@ -839,20 +841,20 @@ namespace Sass { ...@@ -839,20 +841,20 @@ namespace Sass {
each_env.current_frame[iter_var.token()] = eval(list[j], Node(), bindings, ctx.function_env, new_Node, ctx); each_env.current_frame[iter_var.token()] = eval(list[j], Node(), bindings, ctx.function_env, new_Node, ctx);
Node v(eval_function(name, each_body, each_env, new_Node, ctx)); Node v(eval_function(name, each_body, each_env, new_Node, ctx));
if (v.is_null()) continue; if (v.is_null()) continue;
else return v; else return v;
} }
} break; } break;
case Node::while_directive: { case Node::while_directive: {
Node pred_expr(new_Node(stm[0])); Node pred_expr(stm[0]);
Node while_body(stm[1]); Node while_body(stm[1]);
Environment while_env; // re-use this env for each iteration Environment while_env; // re-use this env for each iteration
while_env.link(bindings); while_env.link(bindings);
Node pred_val(eval(pred_expr, Node(), bindings, ctx.function_env, new_Node, ctx)); Node pred_val(eval(pred_expr, Node(), bindings, ctx.function_env, new_Node, ctx));
while ((pred_val.type() != Node::boolean) || pred_val.boolean_value()) { while (!pred_val.is_false()) {
Node v(eval_function(name, while_body, while_env, new_Node, ctx)); Node v(eval_function(name, while_body, while_env, new_Node, ctx));
if (v.is_null()) { if (v.is_null()) {
pred_val = eval(new_Node(stm[0]), Node(), bindings, ctx.function_env, new_Node, ctx); pred_val = eval(pred_expr, Node(), bindings, ctx.function_env, new_Node, ctx);
continue; continue;
} }
else return v; else return v;
...@@ -860,12 +862,9 @@ namespace Sass { ...@@ -860,12 +862,9 @@ namespace Sass {
} break; } break;
case Node::warning: { case Node::warning: {
stm = new_Node(stm);
stm[0] = eval(stm[0], Node(), bindings, ctx.function_env, new_Node, ctx);
string prefix("WARNING: "); string prefix("WARNING: ");
string indent(" "); string indent(" ");
Node contents(stm[0]); Node contents(eval(stm[0], Node(), bindings, ctx.function_env, new_Node, ctx));
string result(contents.to_string()); string result(contents.to_string());
if (contents.type() == Node::string_constant || contents.type() == Node::string_schema) { if (contents.type() == Node::string_constant || contents.type() == Node::string_schema) {
result = result.substr(1, result.size()-2); // unquote if it's a single string result = result.substr(1, result.size()-2); // unquote if it's a single string
...@@ -877,11 +876,13 @@ namespace Sass { ...@@ -877,11 +876,13 @@ namespace Sass {
} break; } break;
case Node::return_directive: { case Node::return_directive: {
Node retval(eval(new_Node(stm[0]), Node(), bindings, ctx.function_env, new_Node, ctx)); Node retval(eval(stm[0], Node(), bindings, ctx.function_env, new_Node, ctx));
if (retval.type() == Node::list) { if (retval.type() == Node::list) {
Node new_list(new_Node(Node::list, retval.path(), retval.line(), retval.size()));
for (size_t i = 0, S = retval.size(); i < S; ++i) { for (size_t i = 0, S = retval.size(); i < S; ++i) {
retval[i] = eval(retval[i], Node(), bindings, ctx.function_env, new_Node, ctx); new_list << eval(retval[i], Node(), bindings, ctx.function_env, new_Node, ctx);
} }
retval = new_list;
} }
return retval; return retval;
} break; } break;
......
...@@ -18,7 +18,7 @@ namespace Sass { ...@@ -18,7 +18,7 @@ namespace Sass {
switch (type()) switch (type())
{ {
case block: case block:
case expansion: case mixin_call:
case root: case root:
case if_directive: case if_directive:
case for_through_directive: case for_through_directive:
...@@ -34,7 +34,7 @@ namespace Sass { ...@@ -34,7 +34,7 @@ namespace Sass {
for (size_t i = 0; i < size(); ++i) { for (size_t i = 0; i < size(); ++i) {
switch (at(i).type()) switch (at(i).type())
{ {
case expansion: case mixin_call:
case block: case block:
case if_directive: case if_directive:
case for_through_directive: case for_through_directive:
......
...@@ -150,11 +150,11 @@ namespace Sass { ...@@ -150,11 +150,11 @@ namespace Sass {
identifier_schema, identifier_schema,
css_import, css_import,
function,
function_call, function_call,
mixin, mixin,
function, mixin_call,
parameters, parameters,
expansion,
arguments, arguments,
if_directive, if_directive,
...@@ -370,7 +370,7 @@ namespace Sass { ...@@ -370,7 +370,7 @@ namespace Sass {
case Node::for_to_directive: case Node::for_to_directive:
case Node::each_directive: case Node::each_directive:
case Node::while_directive: case Node::while_directive:
case Node::expansion: { case Node::mixin_call: {
has_expansions = true; has_expansions = true;
} break; } break;
...@@ -402,7 +402,7 @@ namespace Sass { ...@@ -402,7 +402,7 @@ namespace Sass {
case Node::for_to_directive: case Node::for_to_directive:
case Node::each_directive: case Node::each_directive:
case Node::while_directive: case Node::while_directive:
case Node::expansion: has_expansions = true; break; case Node::mixin_call: has_expansions = true; break;
case Node::backref: has_backref = true; break; case Node::backref: has_backref = true; break;
......
...@@ -271,7 +271,7 @@ namespace Sass { ...@@ -271,7 +271,7 @@ namespace Sass {
return result; return result;
} break; } break;
case expansion: { case mixin_call: {
// ignore it // ignore it
return ""; return "";
} break; } break;
......
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