Commit b19c9594 by Aaron Leung

Updated the builtin functions to use the refactored API.

parent d12389e7
#ifndef SASS_PRELEXER_INCLUDED #ifndef SASS_PRELEXER_INCLUDED
#include "prelexer.hpp" #include "prelexer.hpp"
#endif #endif
#include "node_factory.hpp"
#include "functions.hpp" #include "functions.hpp"
#include "error.hpp" #include "error.hpp"
#include <iostream> #include <iostream>
...@@ -12,7 +13,7 @@ namespace Sass { ...@@ -12,7 +13,7 @@ namespace Sass {
static void throw_eval_error(string message, string path, size_t line) static void throw_eval_error(string message, string path, size_t line)
{ {
if (!path.empty() && Prelexer::string_constant(file_name)) if (!path.empty() && Prelexer::string_constant(path.c_str()))
path = path.substr(1, path.length() - 1); path = path.substr(1, path.length() - 1);
throw Error(Error::evaluation, path, line, message); throw Error(Error::evaluation, path, line, message);
...@@ -53,7 +54,7 @@ namespace Sass { ...@@ -53,7 +54,7 @@ namespace Sass {
Node g(color[1]); Node g(color[1]);
Node b(color[2]); Node b(color[2]);
Node a(bindings[parameters[1]]); Node a(bindings[parameters[1]]);
if (color.type() != Node::numeric_color || a.type != Node::number) throw_eval_error("arguments to rgba must be a color and a number", color.path(), color.line()); if (color.type() != Node::numeric_color || a.type() != Node::number) throw_eval_error("arguments to rgba must be a color and a number", color.path(), color.line());
return new_Node(color.path(), color.line(), r.numeric_value(), g.numeric_value(), b.numeric_value(), a.numeric_value()); return new_Node(color.path(), color.line(), r.numeric_value(), g.numeric_value(), b.numeric_value(), a.numeric_value());
} }
...@@ -186,7 +187,7 @@ namespace Sass { ...@@ -186,7 +187,7 @@ namespace Sass {
{ "invert", "$color", 0 }; { "invert", "$color", 0 };
Node invert(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node invert(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) {
Node orig(bindings[parameters[0]]); Node orig(bindings[parameters[0]]);
if (orig.type() != Node::numeric_color) throw_eval_error("argument to invert must be a color", orig.line_number, orig.file_name); 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(orig.path(), orig.line(),
255 - orig[0].numeric_value(), 255 - orig[0].numeric_value(),
255 - orig[1].numeric_value(), 255 - orig[1].numeric_value(),
...@@ -219,11 +220,11 @@ namespace Sass { ...@@ -219,11 +220,11 @@ namespace Sass {
if (delta.numeric_value() < 0 || delta.numeric_value() > 1) { if (delta.numeric_value() < 0 || delta.numeric_value() > 1) {
throw_eval_error("amount must be between 0 and 1 for opacify/fade-in", delta.path(), delta.line()); throw_eval_error("amount must be between 0 and 1 for opacify/fade-in", delta.path(), delta.line());
} }
double alpha = orig[3].numeric_value() + delta.numeric_value(); double alpha = color[3].numeric_value() + delta.numeric_value();
if (alpha > 1) alpha = 1; if (alpha > 1) alpha = 1;
else if (alpha < 0) alpha = 0; else if (alpha < 0) alpha = 0;
return new_Node(orig.path(), orig.line(), return new_Node(color.path(), color.line(),
orig[0].numeric_value(), orig[1].numeric_value(), orig[2].numeric_value(), alpha); color[0].numeric_value(), color[1].numeric_value(), color[2].numeric_value(), alpha);
} }
Function_Descriptor transparentize_descriptor = Function_Descriptor transparentize_descriptor =
...@@ -234,16 +235,16 @@ namespace Sass { ...@@ -234,16 +235,16 @@ namespace Sass {
Node color(bindings[parameters[0]]); Node color(bindings[parameters[0]]);
Node delta(bindings[parameters[1]]); Node delta(bindings[parameters[1]]);
if (color.type() != Node::numeric_color || !delta.is_numeric()) { if (color.type() != Node::numeric_color || !delta.is_numeric()) {
throw_eval_error("arguments to transparentize/fade_out must be a color and a numeric value", orig.path(), orig.line()); throw_eval_error("arguments to transparentize/fade_out must be a color and a numeric value", color.path(), color.line());
} }
if (delta.numeric_value() < 0 || delta.numeric_value() > 1) { if (delta.numeric_value() < 0 || delta.numeric_value() > 1) {
throw_eval_error("amount must be between 0 and 1 for transparentize/fade-out", delta.path(), delta.line()); throw_eval_error("amount must be between 0 and 1 for transparentize/fade-out", delta.path(), delta.line());
} }
double alpha = orig[3].numeric_value() - delta.numeric_value(); double alpha = color[3].numeric_value() - delta.numeric_value();
if (alpha > 1) alpha = 1; if (alpha > 1) alpha = 1;
else if (alpha < 0) alpha = 0; else if (alpha < 0) alpha = 0;
return new_Node(orig.path(), orig.line(), return new_Node(color.path(), color.line(),
orig[0].numeric_value(), orig[1].numeric_value(), orig[2].numeric_value(), alpha); color[0].numeric_value(), color[1].numeric_value(), color[2].numeric_value(), alpha);
} }
// String Functions //////////////////////////////////////////////////// // String Functions ////////////////////////////////////////////////////
...@@ -266,7 +267,7 @@ namespace Sass { ...@@ -266,7 +267,7 @@ namespace Sass {
if (orig.type() != Node::string_constant && orig.type() != Node::identifier) { if (orig.type() != Node::string_constant && orig.type() != Node::identifier) {
throw_eval_error("argument to quote must be a string or identifier", orig.path(), orig.line()); throw_eval_error("argument to quote must be a string or identifier", orig.path(), orig.line());
} }
Node cpy(new_Node(Node::string_constant, orig.path(), orig.line(), orig.token()) Node cpy(new_Node(orig));
cpy.is_unquoted() = false; cpy.is_unquoted() = false;
return cpy; return cpy;
} }
...@@ -276,76 +277,131 @@ namespace Sass { ...@@ -276,76 +277,131 @@ namespace Sass {
Function_Descriptor percentage_descriptor = Function_Descriptor percentage_descriptor =
{ "percentage", "$value", 0 }; { "percentage", "$value", 0 };
Node percentage(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node percentage(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) {
Node cpy(bindings[parameters[0]].clone(new_Node)); Node orig(bindings[parameters[0]]);
// TO DO: make sure it's not already a percentage if (orig.type() != Node::number) {
if (cpy.type() != Node::number) throw_eval_error("argument to percentage must be a unitless number", cpy.path(), cpy.line()); throw_eval_error("argument to percentage must be a unitless number", orig.path(), orig.line());
cpy.numeric_value() = cpy.numeric_value() * 100; }
cpy.type() = Node::numeric_percentage; return new_Node(orig.path(), orig.line(), orig.numeric_value() * 100, Node::numeric_percentage);
return cpy;
} }
Function_Descriptor round_descriptor = Function_Descriptor round_descriptor =
{ "round", "$value", 0 }; { "round", "$value", 0 };
Node round(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node round(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) {
Node cpy(bindings[parameters[0]].clone(new_Node)); Node orig(bindings[parameters[0]]);
if (cpy.type() == Node::numeric_dimension) { switch (orig.type())
cpy.content.dimension.numeric_value = std::floor(cpy.content.dimension.numeric_value + 0.5); {
} case Node::numeric_dimension: {
else if (cpy.type() == Node::number || cpy.type() == Node::numeric_percentage) { return new_Node(orig.path(), orig.line(),
cpy.numeric_value() = std::floor(cpy.numeric_value() + 0.5); std::floor(orig.numeric_value() + 0.5), orig.unit());
} } break;
else {
throw_eval_error("argument to round must be numeric", cpy.path(), cpy.line()); case Node::number: {
return new_Node(orig.path(), orig.line(),
std::floor(orig.numeric_value() + 0.5));
} break;
case Node::numeric_percentage: {
return new_Node(orig.path(), orig.line(),
std::floor(orig.numeric_value() + 0.5),
Node::numeric_percentage);
} break;
default: {
throw_eval_error("argument to round must be numeric", orig.path(), orig.line());
} break;
} }
return cpy; // unreachable statement
return Node();
} }
Function_Descriptor ceil_descriptor = Function_Descriptor ceil_descriptor =
{ "ceil", "$value", 0 }; { "ceil", "$value", 0 };
Node ceil(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node ceil(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) {
Node cpy(bindings[parameters[0]].clone(new_Node)); Node orig(bindings[parameters[0]]);
if (cpy.type() == Node::numeric_dimension) { switch (orig.type())
cpy.content.dimension.numeric_value = std::ceil(cpy.content.dimension.numeric_value); {
} case Node::numeric_dimension: {
else if (cpy.type() == Node::number || cpy.type() == Node::numeric_percentage){ return new_Node(orig.path(), orig.line(),
cpy.numeric_value() = std::ceil(cpy.numeric_value()); std::ceil(orig.numeric_value()), orig.unit());
} } break;
else {
throw_eval_error("argument to ceil must be numeric", cpy.path(), cpy.line()); case Node::number: {
return new_Node(orig.path(), orig.line(),
std::ceil(orig.numeric_value()));
} break;
case Node::numeric_percentage: {
return new_Node(orig.path(), orig.line(),
std::ceil(orig.numeric_value()),
Node::numeric_percentage);
} break;
default: {
throw_eval_error("argument to ceil must be numeric", orig.path(), orig.line());
} break;
} }
return cpy; // unreachable statement
return Node();
} }
Function_Descriptor floor_descriptor = Function_Descriptor floor_descriptor =
{ "floor", "$value", 0 }; { "floor", "$value", 0 };
Node floor(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node floor(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) {
Node cpy(bindings[parameters[0]].clone(new_Node)); Node orig(bindings[parameters[0]]);
if (cpy.type() == Node::numeric_dimension) { switch (orig.type())
cpy.content.dimension.numeric_value = std::floor(cpy.content.dimension.numeric_value); {
} case Node::numeric_dimension: {
else if (cpy.type() == Node::number || cpy.type() == Node::numeric_percentage){ return new_Node(orig.path(), orig.line(),
cpy.numeric_value() = std::floor(cpy.numeric_value()); std::floor(orig.numeric_value()), orig.unit());
} } break;
else {
throw_eval_error("argument to floor must be numeric", cpy.path(), cpy.line()); case Node::number: {
return new_Node(orig.path(), orig.line(),
std::floor(orig.numeric_value()));
} break;
case Node::numeric_percentage: {
return new_Node(orig.path(), orig.line(),
std::floor(orig.numeric_value()),
Node::numeric_percentage);
} break;
default: {
throw_eval_error("argument to floor must be numeric", orig.path(), orig.line());
} break;
} }
return cpy; // unreachable statement
return Node();
} }
Function_Descriptor abs_descriptor = Function_Descriptor abs_descriptor =
{ "abs", "$value", 0 }; { "abs", "$value", 0 };
Node abs(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node abs(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) {
Node cpy(bindings[parameters[0]].clone(new_Node)); Node orig(bindings[parameters[0]]);
if (cpy.type() == Node::numeric_dimension) { switch (orig.type())
cpy.content.dimension.numeric_value = std::fabs(cpy.content.dimension.numeric_value); {
} case Node::numeric_dimension: {
else if (cpy.type() == Node::number || cpy.type() == Node::numeric_percentage){ return new_Node(orig.path(), orig.line(),
cpy.numeric_value() = std::abs(cpy.numeric_value()); std::abs(orig.numeric_value()), orig.unit());
} } break;
else {
throw_eval_error("argument to abs must be numeric", cpy.path(), cpy.line()); case Node::number: {
return new_Node(orig.path(), orig.line(),
std::abs(orig.numeric_value()));
} break;
case Node::numeric_percentage: {
return new_Node(orig.path(), orig.line(),
std::abs(orig.numeric_value()),
Node::numeric_percentage);
} break;
default: {
throw_eval_error("argument to abs must be numeric", orig.path(), orig.line());
} break;
} }
return cpy; // unreachable statement
return Node();
} }
// List Functions ////////////////////////////////////////////////////// // List Functions //////////////////////////////////////////////////////
...@@ -354,31 +410,46 @@ namespace Sass { ...@@ -354,31 +410,46 @@ namespace Sass {
{ "length", "$list", 0 }; { "length", "$list", 0 };
Node length(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node length(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) {
Node arg(bindings[parameters[0]]); Node arg(bindings[parameters[0]]);
if (arg.type() == Node::space_list || arg.type() == Node::comma_list) { switch (arg.type())
return Node(arg.line_number, arg.size()); {
} case Node::space_list:
else if (arg.type() == Node::nil) { case Node::comma_list: {
return Node(arg.line_number, 0); return new_Node(arg.path(), arg.line(), arg.size());
} } break;
case Node::nil: {
return new_Node(arg.path(), arg.line(), 0);
} break;
default: {
// single objects should be reported as lists of length 1 // single objects should be reported as lists of length 1
else { return new_Node(arg.path(), arg.line(), 1);
return Node(arg.line_number, 1); } break;
} }
// unreachable statement
return Node();
} }
Function_Descriptor nth_descriptor = Function_Descriptor nth_descriptor =
{ "nth", "$list", "$n", 0 }; { "nth", "$list", "$n", 0 };
Node nth(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node nth(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) {
Node l(bindings[parameters[0]]); Node l(bindings[parameters[0]]);
// TO DO: check for empty list Node n(bindings[parameters[1]]);
if (l.type() == Node::nil) throw_eval_error("cannot index into an empty list", l.line_number, l.file_name); if (n.type() != Node::number) {
throw_eval_error("second argument to nth must be a number", n.path(), n.line());
}
if (l.type() == Node::nil) {
throw_eval_error("cannot index into an empty list", l.path(), l.line());
}
// 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 = Node(Node::space_list, new_Node, l.line_number, 1) << l; l = new_Node(Node::space_list, l.path(), l.line(), 1) << l;
} }
Node n(bindings[parameters[1]]); double n_prim = n.numeric_value();
if (n.type() != Node::number) throw_eval_error("second argument to nth must be a number", n.line_number, n.file_name); if (n_prim < 1 || n_prim > l.size()) {
if (n.numeric_value() < 1 || n.numeric_value() > l.size()) throw_eval_error("out of range index for nth", n.line_number, n.file_name); throw_eval_error("out of range index for nth", n.path(), n.line());
return l[bindings[parameters[1]].numeric_value() - 1]; }
return l[n_prim - 1];
} }
extern const char separator_kwd[] = "$separator"; extern const char separator_kwd[] = "$separator";
...@@ -386,33 +457,35 @@ namespace Sass { ...@@ -386,33 +457,35 @@ 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[parameters[0]]); Node l1(bindings[parameters[0]]);
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 = Node(Node::space_list, new_Node, l1.line_number, 1) << l1; l1 = new_Node(Node::space_list, l1.path(), l1.line(), 1) << l1;
} }
Node l2(bindings[parameters[1]]); Node l2(bindings[parameters[1]]);
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) {
l2 = Node(Node::space_list, new_Node, l2.line_number, 1) << l2; l2 = new_Node(Node::space_list, l2.path(), l2.line(), 1) << l2;
}
// nil + nil = nil
if (l1.type() == Node::nil && l2.type() == Node::nil) {
return new_Node(Node::nil, l1.path(), l1.line(), 0);
} }
// nil and nil is nil
if (l1.type() == Node::nil && l2.type() == Node::nil) return Node(Node::nil, new_Node, l1.line_number);
// figure out the combined size in advance // figure out the combined size in advance
size_t size = 0; size_t size = 0;
if (l1.type() != Node::nil) size += l1.size(); if (l1.type() != Node::nil) size += l1.size();
if (l2.type() != Node::nil) size += l2.size(); if (l2.type() != Node::nil) size += l2.size();
// figure out the result type in advance
// accumulate the result Node::Type rtype;
Node lr(l1.type(), new_Node, l1.line_number, size);
if (has_sep) { if (has_sep) {
string sep(bindings[parameters[2]].content.token.unquote()); string sep(bindings[parameters[2]].token().unquote());
if (sep == "comma") lr.type() = Node::comma_list; if (sep == "comma") rtype = Node::comma_list;
else if (sep == "space") lr.type() = Node::space_list; else if (sep == "space") rtype = Node::space_list;
else if (sep == "auto") ; // leave it alone else if (sep == "auto") rtype = l1.type();
else { else {
throw_eval_error("third argument to join must be 'space', 'comma', or 'auto'", l2.line_number, l2.file_name); throw_eval_error("third argument to join must be 'space', 'comma', or 'auto'", l2.path(), l2.line());
} }
} }
else if (l1.type() != Node::nil) lr.type() = l1.type(); else if (l1.type() != Node::nil) rtype = l1.type();
else if (l2.type() != Node::nil) lr.type() = l2.type(); else if (l2.type() != Node::nil) rtype = l2.type();
// accumulate the result
Node lr(new_Node(rtype, l1.path(), l1.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;
...@@ -442,33 +515,35 @@ namespace Sass { ...@@ -442,33 +515,35 @@ namespace Sass {
{ "type-of", "$value", 0 }; { "type-of", "$value", 0 };
Node type_of(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node type_of(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) {
Node val(bindings[parameters[0]]); Node val(bindings[parameters[0]]);
Node type(Node::string_constant, val.line_number, Token::make()); Token type_name;
type.unquoted = true;
switch (val.type()) switch (val.type())
{ {
case Node::number: case Node::number:
case Node::numeric_dimension: case Node::numeric_dimension:
case Node::numeric_percentage: case Node::numeric_percentage: {
type.content.token = Token::make(number_name); type_name = Token::make(number_name);
break; } break;
case Node::boolean: case Node::boolean: {
type.content.token = Token::make(bool_name); type_name = Token::make(bool_name);
break; } break;
case Node::string_constant: case Node::string_constant:
case Node::value_schema: case Node::value_schema: {
type.content.token = Token::make(string_name); type_name = Token::make(string_name);
break; } break;
case Node::numeric_color: case Node::numeric_color: {
type.content.token = Token::make(color_name); type_name = Token::make(color_name);
break; } break;
case Node::comma_list: case Node::comma_list:
case Node::space_list: case Node::space_list:
case Node::nil: case Node::nil: {
type.content.token = Token::make(list_name); type_name = Token::make(list_name);
break; } break;
default: default: {
type.content.token = Token::make(string_name); type_name = Token::make(string_name);
} break;
} }
Node type(new_Node(Node::string_constant, val.path(), val.line(), type_name));
type.is_unquoted() = true;
return type; return type;
} }
...@@ -479,23 +554,23 @@ namespace Sass { ...@@ -479,23 +554,23 @@ namespace Sass {
{ "unit", "$number", 0 }; { "unit", "$number", 0 };
Node unit(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node unit(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) {
Node val(bindings[parameters[0]]); Node val(bindings[parameters[0]]);
Node u(Node::string_constant, val.line_number, Token::make());
switch (val.type()) switch (val.type())
{ {
case Node::number: case Node::number: {
u.content.token = Token::make(empty_str); return new_Node(Node::string_constant, val.path(), val.line(), Token::make(empty_str));
break; } break;
case Node::numeric_percentage:
u.content.token = Token::make(percent_str);
break;
case Node::numeric_dimension: case Node::numeric_dimension:
u.content.token = Token::make(val.content.dimension.unit, Prelexer::identifier(val.content.dimension.unit)); case Node::numeric_percentage: {
break; return new_Node(Node::string_constant, val.path(), val.line(), val.unit());
default: } break;
throw_eval_error("argument to unit must be numeric", val.line_number, val.file_name);
break; default: {
throw_eval_error("argument to unit must be numeric", val.path(), val.line());
} break;
} }
return u; // unreachable statement
return Node();
} }
extern const char true_str[] = "true"; extern const char true_str[] = "true";
...@@ -505,28 +580,23 @@ namespace Sass { ...@@ -505,28 +580,23 @@ namespace Sass {
{ "unitless", "$number", 0 }; { "unitless", "$number", 0 };
Node unitless(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node unitless(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) {
Node val(bindings[parameters[0]]); Node val(bindings[parameters[0]]);
Node result(Node::string_constant, val.line_number, Token::make());
result.unquoted = true;
switch (val.type()) switch (val.type())
{ {
case Node::number: { case Node::number: {
Node T(Node::boolean); return new_Node(Node::boolean, val.path(), val.line(), true);
T.line_number = val.line_number;
T.content.boolean_value = true;
return T;
} break; } break;
case Node::numeric_percentage: case Node::numeric_percentage:
case Node::numeric_dimension: { case Node::numeric_dimension: {
Node F(Node::boolean); return new_Node(Node::boolean, val.path(), val.line(), false);
F.line_number = val.line_number; } break;
F.content.boolean_value = false;
return F; default: {
throw_eval_error("argument to unitless must be numeric", val.path(), val.line());
} break; } break;
default:
throw_eval_error("argument to unitless must be numeric", val.line_number, val.file_name);
break;
} }
return result; // unreachable statement
return Node();
} }
Function_Descriptor comparable_descriptor = Function_Descriptor comparable_descriptor =
...@@ -536,46 +606,30 @@ namespace Sass { ...@@ -536,46 +606,30 @@ namespace Sass {
Node n2(bindings[parameters[1]]); Node n2(bindings[parameters[1]]);
Node::Type t1 = n1.type(); Node::Type t1 = n1.type();
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);
Node T(Node::boolean);
T.line_number = n1.line_number;
T.content.boolean_value = true;
return T;
} }
else if (t1 == Node::numeric_percentage && t2 == Node::numeric_percentage) { else if (t1 == Node::numeric_percentage && t2 == Node::numeric_percentage) {
Node T(Node::boolean); return new_Node(Node::boolean, n1.path(), n1.line(), true);
T.line_number = n1.line_number;
T.content.boolean_value = true;
return T;
} }
else if (t1 == Node::numeric_dimension && t2 == Node::numeric_dimension) { else if (t1 == Node::numeric_dimension && t2 == Node::numeric_dimension) {
string u1(Token::make(n1.content.dimension.unit, Prelexer::identifier(n1.content.dimension.unit)).to_string()); string u1(n1.unit().to_string());
string u2(Token::make(n2.content.dimension.unit, Prelexer::identifier(n2.content.dimension.unit)).to_string()); string u2(n2.unit().to_string());
if (u1 == "ex" && u2 == "ex" || if (u1 == "ex" && u2 == "ex" ||
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")) {
Node T(Node::boolean); return new_Node(Node::boolean, n1.path(), n1.line(), true);
T.line_number = n1.line_number;
T.content.boolean_value = true;
return T;
} }
else { else {
Node F(Node::boolean); return new_Node(Node::boolean, n1.path(), n1.line(), false);
F.line_number = n1.line_number;
F.content.boolean_value = false;
return F;
} }
} }
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.line_number, n1.file_name); throw_eval_error("arguments to comparable must be numeric", n1.path(), n1.line());
} }
// default to false if we missed anything
Node F(Node::boolean); return new_Node(Node::boolean, n1.path(), n1.line(), false);
F.line_number = n1.line_number;
F.content.boolean_value = false;
return F;
} }
// Boolean Functions /////////////////////////////////////////////////// // Boolean Functions ///////////////////////////////////////////////////
...@@ -583,17 +637,11 @@ namespace Sass { ...@@ -583,17 +637,11 @@ namespace Sass {
{ "not", "value", 0 }; { "not", "value", 0 };
Node not_impl(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node not_impl(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) {
Node val(bindings[parameters[0]]); Node val(bindings[parameters[0]]);
if (val.type() == Node::boolean && val.content.boolean_value == false) { if (val.type() == Node::boolean && val.boolean_value() == false) {
Node T(Node::boolean); return new_Node(Node::boolean, val.path(), val.line(), true);
T.line_number = val.line_number;
T.content.boolean_value = true;
return T;
} }
else { else {
Node F(Node::boolean); return new_Node(Node::boolean, val.path(), val.line(), false);
F.line_number = val.line_number;
F.content.boolean_value = false;
return F;
} }
} }
......
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