Commit 044f397e by Aaron Leung

Merge branch 'master' into arg_checking

Conflicts:
	functions.cpp
parents 49ce9835 169243a3
...@@ -148,7 +148,9 @@ namespace Sass { ...@@ -148,7 +148,9 @@ namespace Sass {
return empty_str; return empty_str;
} }
////////////////////////////////////////////////////////////////////////
// RGB Functions /////////////////////////////////////////////////////// // RGB Functions ///////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
extern Signature rgb_sig = "rgb($red, $green, $blue)"; extern Signature rgb_sig = "rgb($red, $green, $blue)";
Node rgb(const Node parameter_names, Environment& bindings, Node_Factory& new_Node, string& path, size_t line) { Node rgb(const Node parameter_names, Environment& bindings, Node_Factory& new_Node, string& path, size_t line) {
...@@ -164,7 +166,7 @@ namespace Sass { ...@@ -164,7 +166,7 @@ namespace Sass {
if (dr < 0 || 255 < dr) throw_eval_error("first argument to 'rgb' must be between 0 and 255", r.path(), r.line()); if (dr < 0 || 255 < dr) throw_eval_error("first argument to 'rgb' must be between 0 and 255", r.path(), r.line());
if (dg < 0 || 255 < dg) throw_eval_error("second argument to 'rgb' must be between 0 and 255", g.path(), g.line()); if (dg < 0 || 255 < dg) throw_eval_error("second argument to 'rgb' must be between 0 and 255", g.path(), g.line());
if (db < 0 || 255 < db) throw_eval_error("third argument to 'rgb' must be between 0 and 255", b.path(), b.line()); if (db < 0 || 255 < db) throw_eval_error("third argument to 'rgb' must be between 0 and 255", b.path(), b.line());
return new_Node(r.path(), r.line(), std::floor(dr), std::floor(dg), std::floor(db), 1.0); return new_Node(path, line, std::floor(dr), std::floor(dg), std::floor(db), 1.0);
} }
extern Signature rgba_4_sig = "rgba($red, $green, $blue, $alpha)"; extern Signature rgba_4_sig = "rgba($red, $green, $blue, $alpha)";
...@@ -185,7 +187,7 @@ namespace Sass { ...@@ -185,7 +187,7 @@ namespace Sass {
if (dg < 0 || 255 < dg) throw_eval_error("second argument to 'rgb' must be between 0 and 255", g.path(), g.line()); if (dg < 0 || 255 < dg) throw_eval_error("second argument to 'rgb' must be between 0 and 255", g.path(), g.line());
if (db < 0 || 255 < db) throw_eval_error("third argument to 'rgb' must be between 0 and 255", b.path(), b.line()); if (db < 0 || 255 < db) throw_eval_error("third argument to 'rgb' must be between 0 and 255", b.path(), b.line());
if (da < 0 || 1 < da) throw_eval_error("fourth argument to 'rgb' must be between 0 and 1", a.path(), a.line()); if (da < 0 || 1 < da) throw_eval_error("fourth argument to 'rgb' must be between 0 and 1", a.path(), a.line());
return new_Node(r.path(), r.line(), std::floor(dr), std::floor(dg), std::floor(db), da); return new_Node(path, line, std::floor(dr), std::floor(dg), std::floor(db), da);
} }
extern Signature rgba_2_sig = "rgba($color, $alpha)"; extern Signature rgba_2_sig = "rgba($color, $alpha)";
...@@ -199,7 +201,7 @@ namespace Sass { ...@@ -199,7 +201,7 @@ namespace Sass {
if (!a.is_numeric()) throw_eval_error("second argument to 'rgba' must be numeric", a.path(), a.line()); if (!a.is_numeric()) throw_eval_error("second argument to 'rgba' must be numeric", a.path(), a.line());
double da = a.numeric_value(); double da = a.numeric_value();
if (da < 0 || 1 < da) throw_eval_error("second argument to 'rgba' must be between 0 and 1", a.path(), a.line()); if (da < 0 || 1 < da) throw_eval_error("second argument to 'rgba' must be between 0 and 1", a.path(), a.line());
return new_Node(color.path(), color.line(), r.numeric_value(), g.numeric_value(), b.numeric_value(), a.numeric_value()); return new_Node(path, line, r.numeric_value(), g.numeric_value(), b.numeric_value(), a.numeric_value());
} }
extern Signature red_sig = "red($color)"; extern Signature red_sig = "red($color)";
...@@ -240,16 +242,18 @@ namespace Sass { ...@@ -240,16 +242,18 @@ namespace Sass {
double w1 = (((w * a == -1) ? w : (w + a)/(1 + w*a)) + 1)/2.0; double w1 = (((w * a == -1) ? w : (w + a)/(1 + w*a)) + 1)/2.0;
double w2 = 1 - w1; double w2 = 1 - w1;
Node mixed(new_Node(Node::numeric_color, color1.path(), color1.line(), 4)); Node mixed(new_Node(Node::numeric_color, path, line, 4));
for (int i = 0; i < 3; ++i) { for (int i = 0; i < 3; ++i) {
mixed << new_Node(mixed.path(), mixed.line(), std::floor(w1*color1[i].numeric_value() + w2*color2[i].numeric_value())); mixed << new_Node(path, line, std::floor(w1*color1[i].numeric_value() + w2*color2[i].numeric_value()));
} }
double alpha = color1[3].numeric_value()*p + color2[3].numeric_value()*(1-p); double alpha = color1[3].numeric_value()*p + color2[3].numeric_value()*(1-p);
mixed << new_Node(mixed.path(), mixed.line(), alpha); mixed << new_Node(path, line, alpha);
return mixed; return mixed;
} }
////////////////////////////////////////////////////////////////////////
// HSL Functions /////////////////////////////////////////////////////// // HSL Functions ///////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
// RGB to HSL helper function so we can do hsl operations. // RGB to HSL helper function so we can do hsl operations.
// (taken from http://www.easyrgb.com) // (taken from http://www.easyrgb.com)
...@@ -362,7 +366,7 @@ namespace Sass { ...@@ -362,7 +366,7 @@ namespace Sass {
rgb_color[1].numeric_value(), rgb_color[1].numeric_value(),
rgb_color[2].numeric_value(), rgb_color[2].numeric_value(),
new_Node)); new_Node));
return new_Node("", 0, hsl_color[0].numeric_value(), Token::make(deg_str)); return new_Node(path, line, hsl_color[0].numeric_value(), Token::make(deg_str));
} }
extern Signature saturation_sig = "saturation($color)"; extern Signature saturation_sig = "saturation($color)";
...@@ -373,7 +377,7 @@ namespace Sass { ...@@ -373,7 +377,7 @@ namespace Sass {
rgb_color[1].numeric_value(), rgb_color[1].numeric_value(),
rgb_color[2].numeric_value(), rgb_color[2].numeric_value(),
new_Node)); new_Node));
return new_Node("", 0, hsl_color[1].numeric_value(), Token::make(percent_str)); return new_Node(path, line, hsl_color[1].numeric_value(), Token::make(percent_str));
} }
extern Signature lightness_sig = "lightness($color)"; extern Signature lightness_sig = "lightness($color)";
...@@ -384,7 +388,7 @@ namespace Sass { ...@@ -384,7 +388,7 @@ namespace Sass {
rgb_color[1].numeric_value(), rgb_color[1].numeric_value(),
rgb_color[2].numeric_value(), rgb_color[2].numeric_value(),
new_Node)); new_Node));
return new_Node("", 0, hsl_color[2].numeric_value(), Token::make(percent_str)); return new_Node(path, line, hsl_color[2].numeric_value(), Token::make(percent_str));
} }
extern Signature adjust_hue_sig = "adjust-hue($color, $degrees)"; extern Signature adjust_hue_sig = "adjust-hue($color, $degrees)";
...@@ -493,7 +497,7 @@ namespace Sass { ...@@ -493,7 +497,7 @@ namespace Sass {
hsl_color[2].numeric_value(), hsl_color[2].numeric_value(),
color[3].numeric_value(), color[3].numeric_value(),
new_Node)); new_Node));
return new_Node(color.path(), color.line(), return new_Node(path, line,
result[0].numeric_value(), result[0].numeric_value(),
result[1].numeric_value(), result[1].numeric_value(),
result[2].numeric_value(), result[2].numeric_value(),
...@@ -513,7 +517,7 @@ namespace Sass { ...@@ -513,7 +517,7 @@ namespace Sass {
hsl_color[2].numeric_value(), hsl_color[2].numeric_value(),
color[3].numeric_value(), color[3].numeric_value(),
new_Node)); new_Node));
return new_Node(color.path(), color.line(), return new_Node(path, line,
result[0].numeric_value(), result[0].numeric_value(),
result[1].numeric_value(), result[1].numeric_value(),
result[2].numeric_value(), result[2].numeric_value(),
...@@ -524,14 +528,16 @@ namespace Sass { ...@@ -524,14 +528,16 @@ namespace Sass {
Node invert(const Node parameter_names, Environment& bindings, Node_Factory& new_Node, string& path, size_t line) { Node invert(const Node parameter_names, Environment& bindings, Node_Factory& new_Node, string& path, size_t line) {
Node orig(bindings[parameter_names[0].token()]); Node orig(bindings[parameter_names[0].token()]);
if (orig.type() != Node::numeric_color) throw_eval_error("argument to 'invert' must be a color", orig.path(), orig.line()); if (orig.type() != Node::numeric_color) throw_eval_error("argument to 'invert' must be a color", orig.path(), orig.line());
return new_Node(orig.path(), orig.line(), return new_Node(path, line,
255 - orig[0].numeric_value(), 255 - orig[0].numeric_value(),
255 - orig[1].numeric_value(), 255 - orig[1].numeric_value(),
255 - orig[2].numeric_value(), 255 - orig[2].numeric_value(),
orig[3].numeric_value()); orig[3].numeric_value());
} }
////////////////////////////////////////////////////////////////////////
// Opacity Functions /////////////////////////////////////////////////// // Opacity Functions ///////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
extern Signature alpha_sig = "alpha($color)"; extern Signature alpha_sig = "alpha($color)";
Node alpha(const Node parameter_names, Environment& bindings, Node_Factory& new_Node, string& path, size_t line) { Node alpha(const Node parameter_names, Environment& bindings, Node_Factory& new_Node, string& path, size_t line) {
...@@ -557,7 +563,7 @@ namespace Sass { ...@@ -557,7 +563,7 @@ namespace Sass {
if (dd < 0 || 1 < dd) throw_eval_error("amount must be between 0 and 1 for 'opacify'", delta.path(), delta.line()); if (dd < 0 || 1 < dd) throw_eval_error("amount must be between 0 and 1 for 'opacify'", delta.path(), delta.line());
dd += color[3].numeric_value(); dd += color[3].numeric_value();
if (dd > 1) dd = 1; if (dd > 1) dd = 1;
return new_Node(color.path(), color.line(), return new_Node(path, line,
color[0].numeric_value(), color[0].numeric_value(),
color[1].numeric_value(), color[1].numeric_value(),
color[2].numeric_value(), color[2].numeric_value(),
...@@ -574,7 +580,7 @@ namespace Sass { ...@@ -574,7 +580,7 @@ namespace Sass {
if (dd < 0 || 1 < dd) throw_eval_error("amount must be between 0 and 1 for 'fade-in'", delta.path(), delta.line()); if (dd < 0 || 1 < dd) throw_eval_error("amount must be between 0 and 1 for 'fade-in'", delta.path(), delta.line());
dd += color[3].numeric_value(); dd += color[3].numeric_value();
if (dd > 1) dd = 1; if (dd > 1) dd = 1;
return new_Node(color.path(), color.line(), return new_Node(path, line,
color[0].numeric_value(), color[0].numeric_value(),
color[1].numeric_value(), color[1].numeric_value(),
color[2].numeric_value(), color[2].numeric_value(),
...@@ -591,7 +597,7 @@ namespace Sass { ...@@ -591,7 +597,7 @@ namespace Sass {
if (dd < 0 || 1 < dd) throw_eval_error("amount must be between 0 and 1 for 'transparentize'", delta.path(), delta.line()); if (dd < 0 || 1 < dd) throw_eval_error("amount must be between 0 and 1 for 'transparentize'", delta.path(), delta.line());
double alpha = color[3].numeric_value() - dd; double alpha = color[3].numeric_value() - dd;
if (alpha < 0) alpha = 0; if (alpha < 0) alpha = 0;
return new_Node(color.path(), color.line(), return new_Node(path, line,
color[0].numeric_value(), color[0].numeric_value(),
color[1].numeric_value(), color[1].numeric_value(),
color[2].numeric_value(), color[2].numeric_value(),
...@@ -608,14 +614,16 @@ namespace Sass { ...@@ -608,14 +614,16 @@ namespace Sass {
if (dd < 0 || 1 < dd) throw_eval_error("amount must be between 0 and 1 for 'fade-out'", delta.path(), delta.line()); if (dd < 0 || 1 < dd) throw_eval_error("amount must be between 0 and 1 for 'fade-out'", delta.path(), delta.line());
double alpha = color[3].numeric_value() - dd; double alpha = color[3].numeric_value() - dd;
if (alpha < 0) alpha = 0; if (alpha < 0) alpha = 0;
return new_Node(color.path(), color.line(), return new_Node(path, line,
color[0].numeric_value(), color[0].numeric_value(),
color[1].numeric_value(), color[1].numeric_value(),
color[2].numeric_value(), color[2].numeric_value(),
alpha); alpha);
} }
////////////////////////////////////////////////////////////////////////
// Other Color Functions /////////////////////////////////////////////// // Other Color Functions ///////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
extern Signature adjust_color_sig = "adjust-color($color, $red: false, $green: false, $blue: false, $hue: false, $saturation: false, $lightness: false, $alpha: false)"; extern Signature adjust_color_sig = "adjust-color($color, $red: false, $green: false, $blue: false, $hue: false, $saturation: false, $lightness: false, $alpha: false)";
Node adjust_color(const Node parameter_names, Environment& bindings, Node_Factory& new_Node, string& path, size_t line) { Node adjust_color(const Node parameter_names, Environment& bindings, Node_Factory& new_Node, string& path, size_t line) {
...@@ -646,7 +654,7 @@ namespace Sass { ...@@ -646,7 +654,7 @@ namespace Sass {
double new_g = color[1].numeric_value() + (g.is_false() ? 0 : g.numeric_value()); double new_g = color[1].numeric_value() + (g.is_false() ? 0 : g.numeric_value());
double new_b = color[2].numeric_value() + (b.is_false() ? 0 : b.numeric_value()); double new_b = color[2].numeric_value() + (b.is_false() ? 0 : b.numeric_value());
double new_a = color[3].numeric_value() + (a.is_false() ? 0 : a.numeric_value()); double new_a = color[3].numeric_value() + (a.is_false() ? 0 : a.numeric_value());
return new_Node("", 0, new_r, new_g, new_b, new_a); return new_Node(path, line, new_r, new_g, new_b, new_a);
} }
else if (!no_hsl) { else if (!no_hsl) {
Node hsl_node(rgb_to_hsl(color[0].numeric_value(), Node hsl_node(rgb_to_hsl(color[0].numeric_value(),
...@@ -665,7 +673,7 @@ namespace Sass { ...@@ -665,7 +673,7 @@ namespace Sass {
} }
else if (!a.is_false()) { else if (!a.is_false()) {
if (!a.is_numeric()) throw_eval_error("argument $alpha of 'adjust-color' must be numeric", a.path(), a.line()); if (!a.is_numeric()) throw_eval_error("argument $alpha of 'adjust-color' must be numeric", a.path(), a.line());
return new_Node("", 0, return new_Node(path, line,
color[0].numeric_value(), color[0].numeric_value(),
color[1].numeric_value(), color[1].numeric_value(),
color[2].numeric_value(), color[2].numeric_value(),
...@@ -707,7 +715,7 @@ namespace Sass { ...@@ -707,7 +715,7 @@ namespace Sass {
double new_g = (g.is_false() ? color[1] : g).numeric_value(); double new_g = (g.is_false() ? color[1] : g).numeric_value();
double new_b = (b.is_false() ? color[2] : b).numeric_value(); double new_b = (b.is_false() ? color[2] : b).numeric_value();
double new_a = (a.is_false() ? color[3] : a).numeric_value(); double new_a = (a.is_false() ? color[3] : a).numeric_value();
return new_Node("", 0, new_r, new_g, new_b, new_a); return new_Node(path, line, new_r, new_g, new_b, new_a);
} }
else if (!no_hsl) { else if (!no_hsl) {
Node hsl_node(rgb_to_hsl(color[0].numeric_value(), Node hsl_node(rgb_to_hsl(color[0].numeric_value(),
...@@ -726,7 +734,7 @@ namespace Sass { ...@@ -726,7 +734,7 @@ namespace Sass {
} }
else if (!a.is_false()) { else if (!a.is_false()) {
if (!a.is_numeric()) throw_eval_error("argument $alpha of 'change-color' must be numeric", a.path(), a.line()); if (!a.is_numeric()) throw_eval_error("argument $alpha of 'change-color' must be numeric", a.path(), a.line());
return new_Node("", 0, return new_Node(path, line,
color[0].numeric_value(), color[0].numeric_value(),
color[1].numeric_value(), color[1].numeric_value(),
color[2].numeric_value(), color[2].numeric_value(),
...@@ -739,7 +747,9 @@ namespace Sass { ...@@ -739,7 +747,9 @@ namespace Sass {
return Node(); return Node();
} }
////////////////////////////////////////////////////////////////////////
// String Functions //////////////////////////////////////////////////// // String Functions ////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
extern Signature unquote_sig = "unquote($string)"; extern Signature unquote_sig = "unquote($string)";
Node unquote(const Node parameter_names, Environment& bindings, Node_Factory& new_Node, string& path, size_t line) { Node unquote(const Node parameter_names, Environment& bindings, Node_Factory& new_Node, string& path, size_t line) {
...@@ -775,7 +785,9 @@ namespace Sass { ...@@ -775,7 +785,9 @@ namespace Sass {
return orig; return orig;
} }
////////////////////////////////////////////////////////////////////////
// Number Functions //////////////////////////////////////////////////// // Number Functions ////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
extern Signature percentage_sig = "percentage($value)"; extern Signature percentage_sig = "percentage($value)";
Node percentage(const Node parameter_names, Environment& bindings, Node_Factory& new_Node, string& path, size_t line) { Node percentage(const Node parameter_names, Environment& bindings, Node_Factory& new_Node, string& path, size_t line) {
...@@ -783,7 +795,7 @@ namespace Sass { ...@@ -783,7 +795,7 @@ namespace Sass {
if (orig.type() != Node::number) { if (orig.type() != Node::number) {
throw_eval_error("argument to percentage must be a unitless number", orig.path(), orig.line()); throw_eval_error("argument to percentage must be a unitless number", orig.path(), orig.line());
} }
return new_Node(orig.path(), orig.line(), orig.numeric_value() * 100, Node::numeric_percentage); return new_Node(path, line, orig.numeric_value() * 100, Node::numeric_percentage);
} }
extern Signature round_sig = "round($value)"; extern Signature round_sig = "round($value)";
...@@ -792,23 +804,23 @@ namespace Sass { ...@@ -792,23 +804,23 @@ namespace Sass {
switch (orig.type()) switch (orig.type())
{ {
case Node::numeric_dimension: { case Node::numeric_dimension: {
return new_Node(orig.path(), orig.line(), return new_Node(path, line,
std::floor(orig.numeric_value() + 0.5), orig.unit()); std::floor(orig.numeric_value() + 0.5), orig.unit());
} break; } break;
case Node::number: { case Node::number: {
return new_Node(orig.path(), orig.line(), return new_Node(path, line,
std::floor(orig.numeric_value() + 0.5)); std::floor(orig.numeric_value() + 0.5));
} break; } break;
case Node::numeric_percentage: { case Node::numeric_percentage: {
return new_Node(orig.path(), orig.line(), return new_Node(path, line,
std::floor(orig.numeric_value() + 0.5), std::floor(orig.numeric_value() + 0.5),
Node::numeric_percentage); Node::numeric_percentage);
} break; } break;
default: { default: {
throw_eval_error("argument to round must be numeric", orig.path(), orig.line()); throw_eval_error("argument to round must be numeric", path, line);
} break; } break;
} }
// unreachable statement // unreachable statement
...@@ -821,23 +833,23 @@ namespace Sass { ...@@ -821,23 +833,23 @@ namespace Sass {
switch (orig.type()) switch (orig.type())
{ {
case Node::numeric_dimension: { case Node::numeric_dimension: {
return new_Node(orig.path(), orig.line(), return new_Node(path, line,
std::ceil(orig.numeric_value()), orig.unit()); std::ceil(orig.numeric_value()), orig.unit());
} break; } break;
case Node::number: { case Node::number: {
return new_Node(orig.path(), orig.line(), return new_Node(path, line,
std::ceil(orig.numeric_value())); std::ceil(orig.numeric_value()));
} break; } break;
case Node::numeric_percentage: { case Node::numeric_percentage: {
return new_Node(orig.path(), orig.line(), return new_Node(path, line,
std::ceil(orig.numeric_value()), std::ceil(orig.numeric_value()),
Node::numeric_percentage); Node::numeric_percentage);
} break; } break;
default: { default: {
throw_eval_error("argument to ceil must be numeric", orig.path(), orig.line()); throw_eval_error("argument to ceil must be numeric", path, line);
} break; } break;
} }
// unreachable statement // unreachable statement
...@@ -850,23 +862,23 @@ namespace Sass { ...@@ -850,23 +862,23 @@ namespace Sass {
switch (orig.type()) switch (orig.type())
{ {
case Node::numeric_dimension: { case Node::numeric_dimension: {
return new_Node(orig.path(), orig.line(), return new_Node(path, line,
std::floor(orig.numeric_value()), orig.unit()); std::floor(orig.numeric_value()), orig.unit());
} break; } break;
case Node::number: { case Node::number: {
return new_Node(orig.path(), orig.line(), return new_Node(path, line,
std::floor(orig.numeric_value())); std::floor(orig.numeric_value()));
} break; } break;
case Node::numeric_percentage: { case Node::numeric_percentage: {
return new_Node(orig.path(), orig.line(), return new_Node(path, line,
std::floor(orig.numeric_value()), std::floor(orig.numeric_value()),
Node::numeric_percentage); Node::numeric_percentage);
} break; } break;
default: { default: {
throw_eval_error("argument to floor must be numeric", orig.path(), orig.line()); throw_eval_error("argument to floor must be numeric", path, line);
} break; } break;
} }
// unreachable statement // unreachable statement
...@@ -879,30 +891,32 @@ namespace Sass { ...@@ -879,30 +891,32 @@ namespace Sass {
switch (orig.type()) switch (orig.type())
{ {
case Node::numeric_dimension: { case Node::numeric_dimension: {
return new_Node(orig.path(), orig.line(), return new_Node(path, line,
std::abs(orig.numeric_value()), orig.unit()); std::abs(orig.numeric_value()), orig.unit());
} break; } break;
case Node::number: { case Node::number: {
return new_Node(orig.path(), orig.line(), return new_Node(path, line,
std::abs(orig.numeric_value())); std::abs(orig.numeric_value()));
} break; } break;
case Node::numeric_percentage: { case Node::numeric_percentage: {
return new_Node(orig.path(), orig.line(), return new_Node(path, line,
std::abs(orig.numeric_value()), std::abs(orig.numeric_value()),
Node::numeric_percentage); Node::numeric_percentage);
} break; } break;
default: { default: {
throw_eval_error("argument to abs must be numeric", orig.path(), orig.line()); throw_eval_error("argument to abs must be numeric", path, line);
} break; } break;
} }
// unreachable statement // unreachable statement
return Node(); return Node();
} }
////////////////////////////////////////////////////////////////////////
// List Functions ////////////////////////////////////////////////////// // List Functions //////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
extern Signature length_sig = "length($list)"; extern Signature length_sig = "length($list)";
Node length(const Node parameter_names, Environment& bindings, Node_Factory& new_Node, string& path, size_t line) { Node length(const Node parameter_names, Environment& bindings, Node_Factory& new_Node, string& path, size_t line) {
...@@ -911,16 +925,16 @@ namespace Sass { ...@@ -911,16 +925,16 @@ namespace Sass {
{ {
case Node::space_list: case Node::space_list:
case Node::comma_list: { case Node::comma_list: {
return new_Node(arg.path(), arg.line(), arg.size()); return new_Node(path, line, arg.size());
} break; } break;
case Node::nil: { case Node::nil: {
return new_Node(arg.path(), arg.line(), 0); return new_Node(path, line, 0);
} break; } break;
default: { default: {
// single objects should be reported as lists of length 1 // single objects should be reported as lists of length 1
return new_Node(arg.path(), arg.line(), 1); return new_Node(path, line, 1);
} break; } break;
} }
// unreachable statement // unreachable statement
...@@ -932,18 +946,18 @@ namespace Sass { ...@@ -932,18 +946,18 @@ namespace Sass {
Node l(bindings[parameter_names[0].token()]); Node l(bindings[parameter_names[0].token()]);
Node n(bindings[parameter_names[1].token()]); Node n(bindings[parameter_names[1].token()]);
if (n.type() != Node::number) { if (n.type() != Node::number) {
throw_eval_error("second argument to nth must be a number", n.path(), n.line()); throw_eval_error("second argument to nth must be a number", path, line);
} }
if (l.type() == Node::nil) { if (l.type() == Node::nil) {
throw_eval_error("cannot index into an empty list", l.path(), l.line()); throw_eval_error("cannot index into an empty list", path, line);
} }
// wrap the first arg if it isn't a list // wrap the first arg if it isn't a list
if (l.type() != Node::space_list && l.type() != Node::comma_list) { if (l.type() != Node::space_list && l.type() != Node::comma_list) {
l = new_Node(Node::space_list, l.path(), l.line(), 1) << l; l = new_Node(Node::space_list, path, line, 1) << l;
} }
double n_prim = n.numeric_value(); double n_prim = n.numeric_value();
if (n_prim < 1 || n_prim > l.size()) { if (n_prim < 1 || n_prim > l.size()) {
throw_eval_error("out of range index for nth", n.path(), n.line()); throw_eval_error("out of range index for nth", path, line);
} }
return l[n_prim - 1]; return l[n_prim - 1];
} }
...@@ -953,7 +967,7 @@ namespace Sass { ...@@ -953,7 +967,7 @@ namespace Sass {
// if the args aren't lists, turn them into singleton lists // if the args aren't lists, turn them into singleton lists
Node l1(bindings[parameter_names[0].token()]); Node l1(bindings[parameter_names[0].token()]);
if (l1.type() != Node::space_list && l1.type() != Node::comma_list && l1.type() != Node::nil) { if (l1.type() != Node::space_list && l1.type() != Node::comma_list && l1.type() != Node::nil) {
l1 = new_Node(Node::space_list, l1.path(), l1.line(), 1) << l1; l1 = new_Node(Node::space_list, path, line, 1) << l1;
} }
Node l2(bindings[parameter_names[1].token()]); Node l2(bindings[parameter_names[1].token()]);
if (l2.type() != Node::space_list && l2.type() != Node::comma_list && l2.type() != Node::nil) { if (l2.type() != Node::space_list && l2.type() != Node::comma_list && l2.type() != Node::nil) {
...@@ -961,7 +975,7 @@ namespace Sass { ...@@ -961,7 +975,7 @@ namespace Sass {
} }
// nil + nil = nil // nil + nil = nil
if (l1.type() == Node::nil && l2.type() == Node::nil) { if (l1.type() == Node::nil && l2.type() == Node::nil) {
return new_Node(Node::nil, l1.path(), l1.line(), 0); return new_Node(Node::nil, path, line, 0);
} }
// figure out the combined size in advance // figure out the combined size in advance
size_t size = 0; size_t size = 0;
...@@ -975,11 +989,11 @@ namespace Sass { ...@@ -975,11 +989,11 @@ namespace Sass {
else if (sep == "space") rtype = Node::space_list; else if (sep == "space") rtype = Node::space_list;
else if (sep == "auto") rtype = l1.type(); else if (sep == "auto") rtype = l1.type();
else { else {
throw_eval_error("third argument to join must be 'space', 'comma', or 'auto'", l2.path(), l2.line()); throw_eval_error("third argument to join must be 'space', 'comma', or 'auto'", path, line);
} }
if (rtype == Node::nil) rtype = l2.type(); if (rtype == Node::nil) rtype = l2.type();
// accumulate the result // accumulate the result
Node lr(new_Node(rtype, l1.path(), l1.line(), size)); Node lr(new_Node(rtype, path, line, size));
if (l1.type() != Node::nil) lr += l1; if (l1.type() != Node::nil) lr += l1;
if (l2.type() != Node::nil) lr += l2; if (l2.type() != Node::nil) lr += l2;
return lr; return lr;
...@@ -997,7 +1011,7 @@ namespace Sass { ...@@ -997,7 +1011,7 @@ namespace Sass {
} break; } break;
// if the first arg isn't a list, wrap it in a singleton // if the first arg isn't a list, wrap it in a singleton
default: { default: {
list = (new_Node(Node::space_list, list.path(), list.line(), 1) << list); list = (new_Node(Node::space_list, path, line, 1) << list);
} break; } break;
} }
...@@ -1006,9 +1020,9 @@ namespace Sass { ...@@ -1006,9 +1020,9 @@ namespace Sass {
if (sep_string == "comma") sep_type = Node::comma_list; if (sep_string == "comma") sep_type = Node::comma_list;
else if (sep_string == "space") sep_type = Node::space_list; else if (sep_string == "space") sep_type = Node::space_list;
else if (sep_string == "auto") sep_type = list.type(); else if (sep_string == "auto") sep_type = list.type();
else throw_eval_error("third argument to append must be 'space', 'comma', or 'auto'", list.path(), list.line()); else throw_eval_error("third argument to append must be 'space', 'comma', or 'auto'", path, line);
Node new_list(new_Node(sep_type, list.path(), list.line(), list.size() + 1)); Node new_list(new_Node(sep_type, path, line, list.size() + 1));
new_list += list; new_list += list;
new_list << bindings[parameter_names[1].token()]; new_list << bindings[parameter_names[1].token()];
return new_list; return new_list;
...@@ -1023,7 +1037,7 @@ namespace Sass { ...@@ -1023,7 +1037,7 @@ namespace Sass {
if (num_args == 1 && (arg1.type() == Node::space_list || if (num_args == 1 && (arg1.type() == Node::space_list ||
arg1.type() == Node::comma_list || arg1.type() == Node::comma_list ||
arg1.type() == Node::nil)) { arg1.type() == Node::nil)) {
list = new_Node(arg1.type(), arg1.path(), arg1.line(), arg1.size()); list = new_Node(arg1.type(), path, line, arg1.size());
list += arg1; list += arg1;
} }
else { else {
...@@ -1038,10 +1052,12 @@ namespace Sass { ...@@ -1038,10 +1052,12 @@ namespace Sass {
new_list << list[i]; new_list << list[i];
} }
} }
return new_list.size() ? new_list : new_Node(Node::nil, list.path(), list.line(), 0); return new_list.size() ? new_list : new_Node(Node::nil, path, line, 0);
} }
////////////////////////////////////////////////////////////////////////
// Introspection Functions ///////////////////////////////////////////// // Introspection Functions /////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
extern Signature type_of_sig = "type-of($value)"; extern Signature type_of_sig = "type-of($value)";
Node type_of(const Node parameter_names, Environment& bindings, Node_Factory& new_Node, string& path, size_t line) { Node type_of(const Node parameter_names, Environment& bindings, Node_Factory& new_Node, string& path, size_t line) {
...@@ -1073,7 +1089,7 @@ namespace Sass { ...@@ -1073,7 +1089,7 @@ namespace Sass {
type_name = Token::make(string_name); type_name = Token::make(string_name);
} break; } break;
} }
Node type(new_Node(Node::string_constant, val.path(), val.line(), type_name)); Node type(new_Node(Node::string_constant, path, line, type_name));
type.is_unquoted() = true; type.is_unquoted() = true;
return type; return type;
} }
...@@ -1084,16 +1100,16 @@ namespace Sass { ...@@ -1084,16 +1100,16 @@ namespace Sass {
switch (val.type()) switch (val.type())
{ {
case Node::number: { case Node::number: {
return new_Node(Node::string_constant, val.path(), val.line(), Token::make(empty_str)); return new_Node(Node::string_constant, path, line, Token::make(empty_str));
} break; } break;
case Node::numeric_dimension: case Node::numeric_dimension:
case Node::numeric_percentage: { case Node::numeric_percentage: {
return new_Node(Node::string_constant, val.path(), val.line(), val.unit()); return new_Node(Node::string_constant, path, line, val.unit());
} break; } break;
default: { default: {
throw_eval_error("argument to unit must be numeric", val.path(), val.line()); throw_eval_error("argument to unit must be numeric", path, line);
} break; } break;
} }
// unreachable statement // unreachable statement
...@@ -1106,16 +1122,16 @@ namespace Sass { ...@@ -1106,16 +1122,16 @@ namespace Sass {
switch (val.type()) switch (val.type())
{ {
case Node::number: { case Node::number: {
return new_Node(Node::boolean, val.path(), val.line(), true); return new_Node(Node::boolean, path, line, true);
} break; } break;
case Node::numeric_percentage: case Node::numeric_percentage:
case Node::numeric_dimension: { case Node::numeric_dimension: {
return new_Node(Node::boolean, val.path(), val.line(), false); return new_Node(Node::boolean, path, line, false);
} break; } break;
default: { default: {
throw_eval_error("argument to unitless must be numeric", val.path(), val.line()); throw_eval_error("argument to unitless must be numeric", path, line);
} break; } break;
} }
// unreachable statement // unreachable statement
...@@ -1130,10 +1146,10 @@ namespace Sass { ...@@ -1130,10 +1146,10 @@ namespace Sass {
Node::Type t2 = n2.type(); Node::Type t2 = n2.type();
if ((t1 == Node::number && n2.is_numeric()) || if ((t1 == Node::number && n2.is_numeric()) ||
(n1.is_numeric() && t2 == Node::number)) { (n1.is_numeric() && t2 == Node::number)) {
return new_Node(Node::boolean, n1.path(), n1.line(), true); return new_Node(Node::boolean, path, line, true);
} }
else if (t1 == Node::numeric_percentage && t2 == Node::numeric_percentage) { else if (t1 == Node::numeric_percentage && t2 == Node::numeric_percentage) {
return new_Node(Node::boolean, n1.path(), n1.line(), true); return new_Node(Node::boolean, path, line, true);
} }
else if (t1 == Node::numeric_dimension && t2 == Node::numeric_dimension) { else if (t1 == Node::numeric_dimension && t2 == Node::numeric_dimension) {
string u1(n1.unit().to_string()); string u1(n1.unit().to_string());
...@@ -1142,28 +1158,31 @@ namespace Sass { ...@@ -1142,28 +1158,31 @@ namespace Sass {
(u1 == "em" && u2 == "em") || (u1 == "em" && u2 == "em") ||
((u1 == "in" || u1 == "cm" || u1 == "mm" || u1 == "pt" || u1 == "pc") && ((u1 == "in" || u1 == "cm" || u1 == "mm" || u1 == "pt" || u1 == "pc") &&
(u2 == "in" || u2 == "cm" || u2 == "mm" || u2 == "pt" || u2 == "pc"))) { (u2 == "in" || u2 == "cm" || u2 == "mm" || u2 == "pt" || u2 == "pc"))) {
return new_Node(Node::boolean, n1.path(), n1.line(), true); return new_Node(Node::boolean, path, line, true);
} }
else { else {
return new_Node(Node::boolean, n1.path(), n1.line(), false); return new_Node(Node::boolean, path, line, false);
} }
} }
else if (!n1.is_numeric() && !n2.is_numeric()) { else if (!n1.is_numeric() && !n2.is_numeric()) {
throw_eval_error("arguments to comparable must be numeric", n1.path(), n1.line()); throw_eval_error("arguments to comparable must be numeric", path, line);
} }
// default to false if we missed anything // default to false if we missed anything
return new_Node(Node::boolean, n1.path(), n1.line(), false); return new_Node(Node::boolean, path, line, false);
} }
////////////////////////////////////////////////////////////////////////
// Boolean Functions /////////////////////////////////////////////////// // Boolean Functions ///////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
extern Signature not_sig = "not($value)"; extern Signature not_sig = "not($value)";
Node not_impl(const Node parameter_names, Environment& bindings, Node_Factory& new_Node, string& path, size_t line) { Node not_impl(const Node parameter_names, Environment& bindings, Node_Factory& new_Node, string& path, size_t line) {
Node val(bindings[parameter_names[0].token()]); Node val(bindings[parameter_names[0].token()]);
if (val.type() == Node::boolean && val.boolean_value() == false) { if (val.type() == Node::boolean && val.boolean_value() == false) {
return new_Node(Node::boolean, val.path(), val.line(), true); return new_Node(Node::boolean, path, line, true);
} }
else { else {
return new_Node(Node::boolean, val.path(), val.line(), false); return new_Node(Node::boolean, path, line, false);
} }
} }
......
...@@ -27,6 +27,21 @@ namespace Sass { ...@@ -27,6 +27,21 @@ namespace Sass {
return ip_cpy; return ip_cpy;
} }
// returns a deep-copy of its argument, but uses the path and line that are passed in
Node_Impl* Node_Factory::alloc_Node_Impl(string& path, size_t line, Node_Impl* ip)
{
Node_Impl* ip_cpy = new Node_Impl(*ip);
pool_.push_back(ip_cpy);
if (ip_cpy->has_children) {
for (size_t i = 0, S = ip_cpy->size(); i < S; ++i) {
Node n(ip_cpy->at(i));
ip_cpy->at(i) = (*this)(path, line, n);
}
}
return ip_cpy;
}
// for cloning nodes // for cloning nodes
Node Node_Factory::operator()(const Node& n1) Node Node_Factory::operator()(const Node& n1)
{ {
...@@ -34,6 +49,15 @@ namespace Sass { ...@@ -34,6 +49,15 @@ namespace Sass {
return Node(ip_cpy); return Node(ip_cpy);
} }
// for cloning nodes and resetting their path and line-number fields
Node Node_Factory::operator()(string& path, size_t line, const Node& n1)
{
Node_Impl* ip_cpy = alloc_Node_Impl(path, line, n1.ip_); // deep-copy the implementation object
ip_cpy->path = path;
ip_cpy->line = line;
return Node(ip_cpy);
}
// for making leaf nodes out of terminals/tokens // for making leaf nodes out of terminals/tokens
Node Node_Factory::operator()(Node::Type type, string path, size_t line, Token t) Node Node_Factory::operator()(Node::Type type, string path, size_t line, Token t)
{ {
......
...@@ -17,9 +17,11 @@ namespace Sass { ...@@ -17,9 +17,11 @@ namespace Sass {
Node_Impl* alloc_Node_Impl(Node::Type type, string file, size_t line); Node_Impl* alloc_Node_Impl(Node::Type type, string file, size_t line);
// returns a deep-copy of its argument // returns a deep-copy of its argument
Node_Impl* alloc_Node_Impl(Node_Impl* ip); Node_Impl* alloc_Node_Impl(Node_Impl* ip);
Node_Impl* alloc_Node_Impl(string& path, size_t line, Node_Impl* ip);
public: public:
// for cloning nodes // for cloning nodes
Node operator()(const Node& n1); Node operator()(const Node& n1);
Node operator()(string& path, size_t line, const Node& n1);
// for making leaf nodes out of terminals/tokens // for making leaf nodes out of terminals/tokens
Node operator()(Node::Type type, string file, size_t line, Token t); Node operator()(Node::Type type, string file, size_t line, Token t);
// for making boolean values or interior nodes that have children // for making boolean values or interior nodes that have children
......
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